├── .dockerignore ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── build-container.yml ├── .gitignore ├── .gitlab-ci.yml ├── .npmignore ├── .nvmrc ├── .prettierignore ├── .solhint.json ├── .solhintignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── Dockerfile ├── LICENSE ├── README.md ├── changelog.md ├── config.modules.sh ├── configs ├── .install │ ├── chain-credentials.json │ ├── configurations.json │ ├── configurations.separate.json │ ├── database-credentials.json │ ├── install-credentials.json │ ├── monitor-credentials.json │ ├── networks-credentials.json │ ├── spammer-credentials.json │ ├── templates │ │ ├── attester-config.json │ │ ├── chains-config.json │ │ ├── indexer │ │ │ ├── btc-indexer-config.json │ │ │ ├── doge-indexer-config.json │ │ │ └── xrp-indexer-config.json │ │ ├── monitor-config.json │ │ ├── spammer │ │ │ ├── btc-spammer-config.json │ │ │ ├── doge-spammer-config.json │ │ │ └── xrp-spammer-config.json │ │ ├── stats-config.json │ │ ├── verifier-client │ │ │ ├── verifier-routes-0-config.json │ │ │ └── verifier-routes-150-config.json │ │ ├── verifier-server │ │ │ ├── btc-verifier-config.json │ │ │ ├── doge-verifier-config.json │ │ │ └── xrp-verifier-config.json │ │ └── webserver-config.json │ ├── verifier-client-credentials.json │ ├── verifier-server-credentials.json │ └── webserver-credentials.json ├── global-configs │ ├── coston │ │ ├── global-0-config.json │ │ └── global-150-config.json │ ├── coston2 │ │ ├── global-0-config.json │ │ └── global-150-config.json │ ├── flare │ │ ├── global-0-config.json │ │ └── global-150-config.json │ └── songbird │ │ ├── global-0-config.json │ │ └── global-150-config.json └── type-definitions │ ├── AddressValidity.json │ ├── BalanceDecreasingTransaction.json │ ├── ConfirmedBlockHeightExists.json │ ├── EVMTransaction.json │ ├── Payment.json │ └── ReferencedPaymentNonexistence.json ├── contracts ├── BitVoting.sol ├── BitVotingTest.sol ├── Merkle.sol ├── StateConnector.sol ├── StateConnectorNew.sol ├── StateConnectorTemp.sol ├── StateConnectorTempTran.sol ├── generated │ ├── contracts │ │ ├── SCProofVerifier.sol │ │ ├── SCProofVerifierBase.sol │ │ ├── SCProofVerifierMock.sol │ │ └── StateConnectorMock.sol │ └── interface │ │ ├── ISCProofVerifier.sol │ │ └── IStateConnector.sol └── scripts │ ├── flatten-fix.ts │ └── flatten.sh ├── devdocs.md ├── docker └── scripts │ ├── attestation-client │ ├── common.sh │ ├── entrypoint.sh │ ├── indexer │ ├── monitor │ ├── spammer │ ├── stats │ ├── verification-server │ └── webserver ├── docs ├── README.md ├── attestation-client │ ├── attestation-client.md │ ├── attestation-configs.md │ ├── attestation-suite.md │ ├── blockchain-nodes.md │ └── env-variables.md ├── attestation-protocol │ ├── attestation-protocol.md │ ├── bit-voting.md │ ├── merkle-tree.md │ ├── message-integrity.md │ ├── state-connector-contract.md │ └── voting-behavior.md ├── config │ ├── config-alerts.md │ ├── config-attester-client.md │ ├── config-backend.md │ ├── config-chains.md │ ├── config-general.md │ ├── config-indexer.md │ ├── config-verifier-router.md │ ├── config-verifier.md │ ├── configuration-system.md │ └── json │ │ ├── json-DatabaseConfiguration.md │ │ ├── json-MCCCreateConfiguration.md │ │ ├── json-NetworkConfiguration.md │ │ └── json-RateLimitingOptions.md ├── end-users │ └── apis.md ├── indexing │ ├── indexer-optimizations.md │ ├── indexer-scope.md │ └── indexer.md ├── installation │ ├── GoogleCloudSecretManager.md │ ├── MaintenanceScripts.md │ └── direct-installation.md ├── misc │ ├── for-developers.md │ ├── for-indexer.md │ ├── indexer-algo-db-clone.md │ ├── node-testnet-installation.md │ ├── service-helpers.md │ ├── testing.md │ ├── update-flare-node.md │ └── update-songbird-node.md ├── monitor │ └── monitor.md ├── node │ └── docker.md ├── testnets │ └── README.md └── verfication │ └── code-generation.md ├── hardhat.config.ts ├── nest-cli.json ├── nginX.default ├── package.json ├── scripts ├── compile.sh ├── direct-install │ ├── files │ │ ├── frontend.env │ │ └── nginx.default │ ├── helpers │ │ ├── indexer-reset-btc.sh │ │ ├── indexer-reset-complete.sh │ │ ├── indexer-reset-doge.sh │ │ ├── indexer-reset-xrp.sh │ │ ├── run-attester-collector-btc.sh │ │ ├── run-attester-collector-xrp.sh │ │ ├── run-attester-spammer-btc.sh │ │ ├── run-attester-spammer-doge.sh │ │ ├── run-attester-spammer-xrp.sh │ │ └── run-attester-spammer.sh │ ├── initialize-credentials.sh │ ├── install-certbot.sh │ ├── install-check.sh │ ├── install-config.sh │ ├── install-dependencies.sh │ ├── install-nginx.sh │ ├── install-nodes-testnet.sh │ ├── install-services.sh │ ├── install.sh │ ├── prepare-credentials.sh │ ├── services-restart-all.sh │ ├── services-stop-all.sh │ ├── services │ │ ├── attester-alerts.service │ │ ├── coston-attester-client.service │ │ ├── coston-backend.service │ │ ├── coston-spammer-btc.service │ │ ├── coston-spammer-doge.service │ │ ├── coston-spammer-xrp.service │ │ ├── coston2-attester-client.service │ │ ├── coston2-backend.service │ │ ├── coston2-web-server.service │ │ ├── flare-attester-client.service │ │ ├── flare-backend.service │ │ ├── indexer-btc.service │ │ ├── indexer-doge.service │ │ ├── indexer-xrp.service │ │ ├── songbird-attester-client.service │ │ ├── songbird-backend.service │ │ ├── songbird-spammer.service │ │ ├── verifier-btc.service │ │ ├── verifier-doge.service │ │ └── verifier-xrp.service │ ├── update-credentials.sh │ └── update.sh ├── grafana │ └── grafana.json └── release │ └── release.sh ├── src ├── admin │ ├── admin.ts │ ├── menu.ts │ ├── menuItem.ts │ ├── menuItemBase.ts │ ├── menuItemCommand.ts │ ├── menuItemLog.ts │ └── menuItemService.ts ├── attester │ ├── Attestation.ts │ ├── AttestationData.ts │ ├── AttestationRound.ts │ ├── AttestationRoundManager.ts │ ├── AttesterClient.ts │ ├── AttesterState.ts │ ├── BitVoteData.ts │ ├── FlareConnection.ts │ ├── FlareDataCollector.ts │ ├── GlobalConfigManager.ts │ ├── configs │ │ ├── AttestationClientConfig.ts │ │ ├── AttesterWebOptions.ts │ │ ├── ChainConfig.ts │ │ └── GlobalAttestationConfig.ts │ ├── experimental │ │ └── IntegerTimeScheduler.ts │ ├── source │ │ ├── SourceManager.ts │ │ └── SourceRouter.ts │ └── types │ │ ├── AttestationRoundEnums.ts │ │ └── AttestationStatus.ts ├── caching │ ├── CachedMccClient.ts │ └── LimitingProcessor.ts ├── choose-subsets-lib │ ├── BitmaskAccumulator.ts │ └── subsets-lib.ts ├── entity-external │ └── DogeExternalEntities.ts ├── entity │ ├── attester │ │ ├── dbAttestationRequest.ts │ │ ├── dbRoundResult.ts │ │ └── dbVotingRoundResult.ts │ ├── base │ │ └── BaseEntity.ts │ └── indexer │ │ ├── dbBlock.ts │ │ ├── dbState.ts │ │ └── dbTransaction.ts ├── external-libs │ ├── AttestationDefinitionStore.ts │ ├── AttestationResponse.ts │ ├── MerkleTree.ts │ ├── config-types.ts │ ├── interfaces.ts │ ├── random.ts │ └── utils.ts ├── indexed-query-manager │ ├── DogeIndexQueryManager.ts │ ├── IIndexedQueryManager.ts │ ├── IndexedQueryManager.ts │ ├── indexed-query-manager-types.ts │ └── random-attestation-requests │ │ ├── README.md │ │ ├── random-ar-00001-payment.ts │ │ ├── random-ar-00002-balance-decreasing-transaction.ts │ │ ├── random-ar-00003-confirmed-block-height-exists.ts │ │ ├── random-ar-00004-referenced-payment-nonexistence.ts │ │ ├── random-ar.ts │ │ └── random-query.ts ├── indexer │ ├── IndexerConfig.ts │ ├── UnconfirmedBlockManager.ts │ ├── blockProcessorManager.ts │ ├── chain-collector-helpers │ │ ├── augmentBlock.ts │ │ ├── augmentTransaction.ts │ │ ├── blockProcessor.ts │ │ └── types.ts │ ├── headerCollector.ts │ ├── indexer-utils.ts │ ├── indexer.ts │ ├── indexerSync.ts │ ├── indexerToClient.ts │ ├── indexerToDB.ts │ ├── interlacing.ts │ └── preparedBlock.ts ├── install │ ├── getSecureValue.ts │ ├── install-file.ts │ ├── install.ts │ ├── installCredentials.ts │ ├── prepareSecureCredentials.ts │ ├── secureCommand.ts │ ├── secureConfigurations.ts │ ├── secureCredentials.ts │ ├── secureUpdateSql.ts │ └── utils.ts ├── monitor │ ├── DockerStats.ts │ ├── MonitorBase.ts │ ├── MonitorConfigBase.ts │ ├── MonitorConfiguration.ts │ ├── MonitorManager.ts │ ├── monitors │ │ ├── AttestationMonitor.ts │ │ ├── DatabaseMonitor.ts │ │ ├── DockerMonitor.ts │ │ ├── IndexerMonitor.ts │ │ ├── NodeMonitor.ts │ │ ├── SystemMonitor.ts │ │ ├── UrlMonitor.ts │ │ └── Web3BalanceMonitor.ts │ └── prometheus.ts ├── runAttestationClient.ts ├── runDockerStats.ts ├── runIndexer.ts ├── runMonitor.ts ├── runVerifierServer.ts ├── runWebServer.ts ├── scripts │ ├── create-routes-folder.ts │ └── deploy-bit-voting.ts ├── servers │ ├── common │ │ ├── src │ │ │ ├── api-models │ │ │ │ ├── ApiBase.ts │ │ │ │ ├── ApiResponse.ts │ │ │ │ ├── PaginatedList.ts │ │ │ │ ├── PaginationRequest.ts │ │ │ │ └── index.ts │ │ │ ├── common.module.ts │ │ │ ├── index.ts │ │ │ └── utils │ │ │ │ └── open-api-utils.ts │ │ └── tsconfig.lib.json │ ├── monitor-server │ │ ├── src │ │ │ ├── config-models │ │ │ │ └── MonitorserverConfig.ts │ │ │ ├── controllers │ │ │ │ └── prometheus.controller.ts │ │ │ ├── dtos │ │ │ │ ├── ServiceStatus.dto.ts │ │ │ │ └── SystemStatus.dto.ts │ │ │ ├── main.ts │ │ │ ├── monitor-server.module.ts │ │ │ ├── monitorserver.ts │ │ │ └── services │ │ │ │ ├── prometheus-engine.service.ts │ │ │ │ └── server-configuration.service.ts │ │ └── tsconfig.app.json │ ├── verifier-server │ │ ├── src │ │ │ ├── auth │ │ │ │ └── auth-header-api-key.strategy.ts │ │ │ ├── config-models │ │ │ │ ├── ServerUser.ts │ │ │ │ └── VerifierServerConfig.ts │ │ │ ├── controllers │ │ │ │ ├── btc │ │ │ │ │ ├── btc-address-validity-verifier.controller.ts │ │ │ │ │ ├── btc-balance-decreasing-transaction-verifier.controller.ts │ │ │ │ │ ├── btc-confirmed-block-height-exists-verifier.controller.ts │ │ │ │ │ ├── btc-indexer.controller.ts │ │ │ │ │ ├── btc-payment-verifier.controller.ts │ │ │ │ │ └── btc-referenced-payment-nonexistence-verifier.controller.ts │ │ │ │ ├── doge │ │ │ │ │ ├── doge-address-validity-verifier.controller.ts │ │ │ │ │ ├── doge-balance-decreasing-transaction-verifier.controller.ts │ │ │ │ │ ├── doge-confirmed-block-height-exists-verifier.controller.ts │ │ │ │ │ ├── doge-indexer.controller.ts │ │ │ │ │ ├── doge-payment-verifier.controller.ts │ │ │ │ │ └── doge-referenced-payment-nonexistence-verifier.controller.ts │ │ │ │ └── xrp │ │ │ │ │ ├── xrp-address-validity-verifier.controller.ts │ │ │ │ │ ├── xrp-balance-decreasing-transaction-verifier.controller.ts │ │ │ │ │ ├── xrp-confirmed-block-height-exists-verifier.controller.ts │ │ │ │ │ ├── xrp-indexer.controller.ts │ │ │ │ │ ├── xrp-payment-verifier.controller.ts │ │ │ │ │ └── xrp-referenced-payment-nonexistence-verifier.controller.ts │ │ │ ├── dtos │ │ │ │ ├── attestation-types │ │ │ │ │ ├── AddressValidity.dto.ts │ │ │ │ │ ├── BalanceDecreasingTransaction.dto.ts │ │ │ │ │ ├── ConfirmedBlockHeightExists.dto.ts │ │ │ │ │ ├── Payment.dto.ts │ │ │ │ │ └── ReferencedPaymentNonexistence.dto.ts │ │ │ │ ├── generic │ │ │ │ │ └── generic.dto.ts │ │ │ │ └── indexer │ │ │ │ │ ├── ApiDbBlock.ts │ │ │ │ │ ├── ApiDbState.ts │ │ │ │ │ ├── ApiDbTransaction.ts │ │ │ │ │ ├── BlockRange.dto.ts │ │ │ │ │ └── QueryTransaction.dto.ts │ │ │ ├── example-data │ │ │ │ ├── AddressValidity.json │ │ │ │ ├── BalanceDecreasingTransaction.json │ │ │ │ ├── ConfirmedBlockHeightExists.json │ │ │ │ ├── Payment.json │ │ │ │ └── ReferencedPaymentNonexistence.json │ │ │ ├── main.ts │ │ │ ├── services │ │ │ │ ├── btc │ │ │ │ │ ├── btc-address-validity-verifier.service.ts │ │ │ │ │ ├── btc-balance-decreasing-transaction-verifier.service.ts │ │ │ │ │ ├── btc-confirmed-block-height-exists-verifier.service.ts │ │ │ │ │ ├── btc-payment-verifier.service.ts │ │ │ │ │ └── btc-referenced-payment-nonexistence-verifier.service.ts │ │ │ │ ├── doge │ │ │ │ │ ├── doge-address-validity-verifier.service.ts │ │ │ │ │ ├── doge-balance-decreasing-transaction-verifier.service.ts │ │ │ │ │ ├── doge-confirmed-block-height-exists-verifier.service.ts │ │ │ │ │ ├── doge-payment-verifier.service.ts │ │ │ │ │ └── doge-referenced-payment-nonexistence-verifier.service.ts │ │ │ │ ├── external-indexer.service.ts │ │ │ │ ├── indexer-engine.service.ts │ │ │ │ ├── verifier-configuration.service.ts │ │ │ │ ├── verifier-processors │ │ │ │ │ ├── btc-processor.service.ts │ │ │ │ │ ├── doge-processor.service.ts │ │ │ │ │ └── xrp-processor.service.ts │ │ │ │ └── xrp │ │ │ │ │ ├── xrp-address-validity-verifier.service.ts │ │ │ │ │ ├── xrp-balance-decreasing-transaction-verifier.service.ts │ │ │ │ │ ├── xrp-confirmed-block-height-exists-verifier.service.ts │ │ │ │ │ ├── xrp-payment-verifier.service.ts │ │ │ │ │ └── xrp-referenced-payment-nonexistence-verifier.service.ts │ │ │ ├── utils │ │ │ │ ├── db-config.ts │ │ │ │ └── validators │ │ │ │ │ ├── Hash32Validator.ts │ │ │ │ │ └── NumberLikeValidator.ts │ │ │ ├── verification │ │ │ │ ├── address-validity.ts │ │ │ │ ├── address-validity │ │ │ │ │ ├── address-validity-btc.ts │ │ │ │ │ ├── address-validity-doge.ts │ │ │ │ │ ├── address-validity-xrp.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── generic-chain-verifications.ts │ │ │ │ └── verification-utils.ts │ │ │ ├── verifier-btc-server.module.ts │ │ │ ├── verifier-doge-server.module.ts │ │ │ ├── verifier-xrp-server.module.ts │ │ │ └── verifierServer.ts │ │ └── tsconfig.app.json │ └── web-server │ │ ├── src │ │ ├── config-models │ │ │ └── WebserverConfig.ts │ │ ├── controllers │ │ │ └── proof.controller.ts │ │ ├── dtos │ │ │ ├── SpecificProofRequest.dto.ts │ │ │ ├── SystemStatus.dto.ts │ │ │ ├── VotingRoundRequest.dto.ts │ │ │ ├── VotingRoundResult.dto.ts │ │ │ └── attestation-types │ │ │ │ ├── AddressValidity.ts │ │ │ │ ├── BalanceDecreasingTransaction.ts │ │ │ │ ├── ConfirmedBlockHeightExists.ts │ │ │ │ ├── EVMTransaction.ts │ │ │ │ ├── Payment.ts │ │ │ │ └── ReferencedPaymentNonexistence.ts │ │ ├── main.ts │ │ ├── services │ │ │ ├── proof-engine.service.ts │ │ │ └── server-configuration.service.ts │ │ ├── utils │ │ │ └── db-config.ts │ │ ├── web-server.module.ts │ │ └── webserver.ts │ │ └── tsconfig.app.json ├── spammer │ ├── README.md │ ├── SpammerConfiguration.ts │ ├── attestation-spammer.ts │ └── flarelocalnode │ │ ├── launch_localnet_scdev.sh │ │ ├── readme.md │ │ └── scdev.json ├── state-collector-finalizer │ ├── deploy-temp-state-connector.ts │ ├── main.ts │ └── state-connector-validator-bot.ts ├── type-definitions │ ├── BalanceDecreasingTransaction.json │ ├── ConfirmedBlockHeightExists.json │ ├── Payment.json │ └── ReferencedPaymentNonexistence.json ├── utils │ ├── compression │ │ ├── compression.ts │ │ └── compression.zlib.ts │ ├── config │ │ ├── config.ts │ │ ├── configSecure.ts │ │ ├── credentialsKey.ts │ │ ├── json.ts │ │ └── jsonSecure.ts │ ├── data-structures │ │ ├── EpochSettings.ts │ │ └── Queue.ts │ ├── database │ │ ├── DatabaseConnectOptions.ts │ │ ├── DatabaseService.ts │ │ └── databaseEntities.ts │ ├── helpers │ │ ├── PromiseRequestManager.ts │ │ ├── PromiseRequestsHandler.ts │ │ ├── Web3Functions.ts │ │ ├── crypto-utils.ts │ │ ├── internetTime.ts │ │ ├── promiseRequestTypes.ts │ │ ├── promiseTimeout.ts │ │ ├── utils.ts │ │ └── web3-utils.ts │ ├── logging │ │ ├── ColorConsole.ts │ │ ├── logger.ts │ │ └── testLogger.ts │ ├── monitoring │ │ ├── Docker.ts │ │ ├── EServiceStatus.ts │ │ ├── ServiceStatus.ts │ │ └── Terminal.ts │ ├── reflection │ │ ├── IInstantiate.ts │ │ ├── reflection.ts │ │ └── typeReflection.ts │ └── security │ │ └── encrypt.ts └── verification │ ├── attestation-types │ ├── attestation-types-helpers.ts │ └── attestation-types.ts │ └── routing │ ├── VerifierRouter.ts │ └── configs │ ├── VerifierAttestationTypeRouteConfig.ts │ ├── VerifierRouteConfig.ts │ └── VerifierSourceRouteConfig.ts ├── test-1020-accounts.json ├── test ├── addressValidity │ ├── btcAddress.test.ts │ ├── dogeAddress.test.ts │ └── xrpAddress.test.ts ├── attestationClient │ ├── AttestationClient.e2e-test.ts │ ├── attestation.test.ts │ ├── attestationClient.test.ts │ ├── attestationData.test.ts │ ├── attestationRound-slower.test.ts │ ├── attestationRound.test.ts │ ├── attestationRoundManager.test.ts │ ├── attesterClientIntegration.test-slow.ts │ ├── attesterState.test.ts │ ├── bitVoteData.test.ts │ ├── flareConnection.test.ts │ ├── globalConfigManager.test.ts │ ├── sourceRouter.test.ts │ ├── test-data │ │ ├── global-configs │ │ │ ├── global-0-config.json │ │ │ └── global-150-config.json │ │ └── templates │ │ │ ├── attester_0-config.json │ │ │ ├── attester_1-config.json │ │ │ ├── attester_2-config.json │ │ │ ├── attester_3-config.json │ │ │ ├── attester_4-config.json │ │ │ ├── attester_5-config.json │ │ │ ├── attester_6-config.json │ │ │ ├── attester_7-config.json │ │ │ ├── attester_8-config.json │ │ │ ├── spammer │ │ │ └── btc-spammer-config.json │ │ │ ├── verifier-client │ │ │ ├── verifier-routes-11-config.json │ │ │ └── verifier-routes-150-config.json │ │ │ ├── verifier-server │ │ │ ├── btc-verifier-config.json │ │ │ ├── doge-verifier-config.json │ │ │ └── xrp-verifier-config.json │ │ │ └── webserver-config.json │ └── utils │ │ ├── attestation-client-test-utils.ts │ │ ├── createEvents.ts │ │ ├── mockClasses.ts │ │ ├── run-attester-spammer-btc.sh │ │ ├── runTestAttestationClient.ts │ │ └── runTestWebServer.ts ├── caching │ ├── CachedBtcMccClient.test-cred.ts │ ├── CachedMccClient.test-slow.ts │ ├── CachedMccClient.test.ts │ ├── LimitingProcessor.test.ts │ └── test-utils │ │ ├── MockMccClient.ts │ │ ├── btc-block-header.json │ │ ├── btc-block-response.json │ │ ├── btc-tx-response.json │ │ ├── xrp-block-response.json │ │ └── xrp-tx-response.json ├── choose-subsets │ ├── BitmaskAccumulator.test.ts │ └── combinators.test.ts ├── contracts │ └── BitVoting.test-contract.ts ├── indexed-query-manager │ ├── IndexedQueryManager.test.ts │ ├── IndexedQueryManager2.test.ts │ ├── RandomTxGenerator.test-dev.ts │ ├── test-data │ │ ├── btc-payment-many-inputs.json │ │ ├── btc-payment-with-reference-1.json │ │ ├── btc-payment-with-reference-2.json │ │ ├── btc-payment.json │ │ ├── templates │ │ │ └── verifier-server │ │ │ │ └── xrp-verifier-config.json │ │ ├── xrp-account-set.json │ │ ├── xrp-offer-create.json │ │ ├── xrp-payment-reference.json │ │ └── xrp-payment.json │ └── utils │ │ └── indexerTestDataGenerator.ts ├── indexer │ ├── blockProcessorManager.test-cred.ts │ ├── blockProcessorManager.test.ts │ ├── blockValidityCheck.test-slow.ts │ ├── chain-collector-helper.test-cred.ts │ ├── chain-collector-helper.test.ts │ ├── chainCollector.test-dev.ts │ ├── headerCollector.test-cred.ts │ ├── headerCollector.test.ts │ ├── indexer-utils.test.ts │ ├── indexer.test.ts │ ├── indexerSync.test-slow.ts │ ├── indexerToClient.test-cred.ts │ ├── indexerToClient.test.ts │ ├── indexerToDB.test.ts │ ├── interlacing.test.ts │ ├── preparedBlock.test.ts │ └── unconfirmedBlockManager.test.ts ├── mockData │ ├── BTCBlock.json │ ├── BTCBlockAlt.json │ ├── BTCBlockHeader.json │ ├── BTCBlockHeaderAlt.json │ ├── BTCTx.json │ ├── BTCTxAlt.json │ ├── BTCTxFake.json │ ├── DOGEBlock.json │ ├── LTCBlockHeaderFake.json │ ├── XRPBlock.json │ ├── XRPBlock612.json │ ├── XRPBlock613.json │ ├── XRPBlock614.json │ ├── XRPBlockAlt.json │ ├── XRPBlockFake.json │ ├── XRPStatus.json │ ├── XRPStatusAlt.json │ ├── XRPTx.json │ └── indexMock.ts ├── random-example-generators │ ├── AddressValidity.ts │ ├── BalanceDecreasingTransaction.ts │ ├── ConfirmedBlockHeightExists.ts │ ├── Payment.ts │ └── ReferencedPaymentNonexistence.ts ├── server │ ├── btc-verifier-server.test-dev.ts │ ├── btc-verifier-server.test.ts │ ├── dev-test-data │ │ ├── db │ │ │ ├── attester_0.db │ │ │ ├── attester_0.db-shm │ │ │ ├── attester_0.db-wal │ │ │ ├── xrp-verifer.db-shm │ │ │ └── xrp-verifer.db-wal │ │ └── templates │ │ │ ├── verifier-server │ │ │ ├── btc-verifier-config.json │ │ │ ├── doge-verifier-config.json │ │ │ └── xrp-verifier-config.json │ │ │ └── webserver-config.json │ ├── doge-verifier-server.test.doge.ts │ ├── test-data │ │ ├── db │ │ │ └── attester_0.db │ │ ├── templates │ │ │ ├── verifier-server │ │ │ │ ├── btc-verifier-config.json │ │ │ │ ├── doge-verifier-config.json │ │ │ │ └── xrp-verifier-config.json │ │ │ └── webserver-config.json │ │ └── test-doge-db-docker.yml │ ├── utils │ │ └── server-test-utils.ts │ ├── web-server.test.ts │ └── xrp-verifier-server.test.ts ├── test-utils │ └── test-utils.ts ├── types │ └── @openzeppelin │ │ ├── index.d.ts │ │ └── test-helpers.d.ts ├── utils │ ├── EpochSettings.test.ts │ ├── PromiseRequestManager.test.ts │ ├── Queue.test.ts │ ├── compression.test.ts │ ├── configuration.test.ts │ ├── credentials.test.ts │ ├── databaseService.test.ts │ ├── googleCloudSecretManager.test-dev.ts │ ├── internetTime.test.ts │ ├── promiseTimeout.test.ts │ ├── reflection.test.ts │ └── test-data │ │ ├── config │ │ ├── keys1-credentials.json │ │ ├── keys2-credentials.json │ │ └── templates │ │ │ ├── env_test-config.json │ │ │ ├── template1-config.json │ │ │ └── template1-credentials.json │ │ ├── credentials.key │ │ └── json_test_eol_comment.json └── verification │ ├── attestationTypeHelpers.test.ts │ ├── miscTests.test.ts │ ├── test-data │ └── templates │ │ ├── verifier-client │ │ └── verifier-routes-150-config.json │ │ └── verifier-server │ │ ├── btc-verifier-config.json │ │ ├── doge-verifier-config.json │ │ └── xrp-verifier-config.json │ ├── test-utils │ └── verifier-test-utils.ts │ └── verifierRouter.test.ts ├── tsconfig.build.json ├── tsconfig.json ├── tslint.json ├── typedoc.config.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | cache 4 | coverage 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: false, 4 | es2021: true, 5 | mocha: true, 6 | node: true, 7 | }, 8 | plugins: [ 9 | "@typescript-eslint", 10 | "node", 11 | ], 12 | extends: [ 13 | // "standard", 14 | // "plugin:prettier/recommended", 15 | // "plugin:node/recommended", 16 | ], 17 | parser: "@typescript-eslint/parser", 18 | parserOptions: { 19 | ecmaVersion: 12, 20 | project: './tsconfig.json', 21 | }, 22 | rules: { 23 | "node/no-unsupported-features/es-syntax": ["error", { ignores: ["modules"] }], 24 | 'guard-for-in': 'warn', 25 | // 'eqeqeq': ['warn', 'always', { null: 'ignore' }], 26 | '@typescript-eslint/await-thenable': 'warn', 27 | '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], 28 | 'no-fallthrough': 'error', 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### VisualStudioCode template 2 | .vscode/* 3 | !.vscode/settings.json 4 | !.vscode/tasks.json 5 | !.vscode/launch.json 6 | !.vscode/extensions.json 7 | 8 | # sqlite db 9 | !./indexer 10 | !./indexer-journal 11 | 12 | # Typescript 13 | /dist 14 | 15 | ## Build generated 16 | /build 17 | /bin 18 | /tmp_data 19 | /tmp 20 | 21 | ## Node packages etc 22 | node_modules/ 23 | 24 | ## code coverage files 25 | coverage.json 26 | .nyc_output/ 27 | /coverage 28 | 29 | ## hardhat? 30 | /cache 31 | 32 | ## yarn 33 | yarn-error.log 34 | 35 | ## Logs 36 | /logs 37 | *.log 38 | 39 | ## test databases 40 | /db 41 | # !./test/server/dev-test-data/db 42 | 43 | ## Misc 44 | nul 45 | .stateconnector-address 46 | .tmp-state-connector-address 47 | .attestation-client-address 48 | .env.att-client-deploy 49 | .DS_Store 50 | .env 51 | 52 | ## Solidity 53 | /artifacts 54 | 55 | ## Typechain 56 | /typechain-truffle 57 | /typechain-web3-v1 58 | # typechain-web3-v1-external 59 | 60 | 61 | # local node 62 | .node/ 63 | 64 | # deployment nodes 65 | deployment/node-configs/testnet/bitcoin/bitcoin.conf 66 | deployment/node-configs/testnet/dogecoin/dogecoin.conf 67 | 68 | # local configs 69 | # .indexer.remote.dev.read.env 70 | # .indexer.remote.dev.write.env 71 | 72 | /flattened 73 | 74 | # alerts 75 | status.json 76 | 77 | # Auto generated docs 78 | /genDocs 79 | 80 | # temp 81 | temp 82 | 83 | # tests 84 | test/utils/test-data/config/credentials.json.secure 85 | 86 | # dockerication mapping test folder 87 | credentials 88 | credentials.prepared 89 | prepare.secure 90 | 91 | *.conf 92 | 93 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | hardhat.config.ts 2 | scripts 3 | test 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.20.0 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | cache 4 | coverage* 5 | gasReporterOutput.json 6 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "compiler-version": ["error", "^0.8.0"], 5 | "func-visibility": ["warn", { "ignoreConstructors": true }] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.preferences.importModuleSpecifier": "relative", 3 | "workbench.colorCustomizations": { 4 | "activityBar.activeBackground": "#2f8c8c", 5 | "activityBar.activeBorder": "#772877", 6 | "activityBar.background": "#2f8c8c", 7 | "activityBar.foreground": "#e7e7e7", 8 | "activityBar.inactiveForeground": "#e7e7e799", 9 | "activityBarBadge.background": "#772877", 10 | "activityBarBadge.foreground": "#e7e7e7", 11 | "sash.hoverBorder": "#2f8c8c", 12 | "statusBar.background": "#226666", 13 | "statusBar.foreground": "#e7e7e7", 14 | "statusBarItem.hoverBackground": "#2f8c8c", 15 | "statusBarItem.remoteBackground": "#226666", 16 | "statusBarItem.remoteForeground": "#e7e7e7", 17 | "titleBar.activeBackground": "#226666", 18 | "titleBar.activeForeground": "#e7e7e7", 19 | "titleBar.inactiveBackground": "#22666699", 20 | "titleBar.inactiveForeground": "#e7e7e799", 21 | "commandCenter.border": "#e7e7e799" 22 | }, 23 | "peacock.color": "#226666", 24 | "audioCues.enabled": "off", 25 | "cSpell.words": ["Merkle"] 26 | } 27 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "docker-build", 6 | "label": "docker-build", 7 | "platform": "node", 8 | "dockerBuild": { 9 | "dockerfile": "${workspaceFolder}/Dockerfile", 10 | "context": "${workspaceFolder}", 11 | "pull": true 12 | } 13 | }, 14 | { 15 | "type": "docker-run", 16 | "label": "docker-run: release", 17 | "dependsOn": [ 18 | "docker-build" 19 | ], 20 | "platform": "node" 21 | }, 22 | { 23 | "type": "docker-run", 24 | "label": "docker-run: debug", 25 | "dependsOn": [ 26 | "docker-build" 27 | ], 28 | "dockerRun": { 29 | "env": { 30 | "DEBUG": "*", 31 | "NODE_ENV": "development" 32 | } 33 | }, 34 | "node": { 35 | "enableDebugging": true 36 | } 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # docker build -t attestation-suite . 2 | # docker-compose -f docker-compose-indexer-btc.yaml up 3 | 4 | 5 | FROM node:16-bullseye 6 | WORKDIR /app/attestation-client 7 | COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "yarn.lock", "./"] 8 | ENV DEBIAN_FRONTEND=noninteractive 9 | RUN \ 10 | apt-get update && \ 11 | curl -L -o /tmp/mysql-apt-config.deb https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb && \ 12 | apt-get install lsb-release -y && \ 13 | dpkg -i /tmp/mysql-apt-config.deb && \ 14 | apt-get update && \ 15 | apt-get -y install mysql-client && \ 16 | yarn install --frozen-lockfile 17 | COPY . . 18 | RUN yarn c && yarn build 19 | EXPOSE 3000 20 | # RUN chown -R node /app/attestation-client 21 | RUN mkdir -p /app/attestation-client/logs && chown -R node /app/attestation-client/logs 22 | USER node 23 | 24 | ENV PATH="${PATH}:/app/attestation-client/docker/scripts" 25 | ENV NODE_ENV=production 26 | 27 | ENTRYPOINT [ "/app/attestation-client/docker/scripts/entrypoint.sh" ] 28 | CMD [ "indexer" ] 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Flare Foundation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Attestation suite change log 2 | 3 | # Version 4.0.0 4 | 5 | - Newer version of Multi-chain-client library is used (4.0.1) with many updates. 6 | - Updated Attestation protocol adoption (see: https://github.com/flare-foundation/songbird-state-connector-protocol). 7 | - New encoding 8 | - Updated attestation types 9 | - Updated indexers. 10 | - External Doge indexer adoption. 11 | - Eip-1559 compliance for submissions. 12 | 13 | # Version 3.0.0 14 | 15 | - Attestation type definitions were changed (see: https://github.com/flare-foundation/state-connector-attestation-types) 16 | - Verification code made more secure for certain edge cases. 17 | - Attestation client code does not depend anymore on specific code generated from attestation type definitions. 18 | - Newer version of Multi-chain-client library is used (3.0.2) with many updates. 19 | - Deployment management utility scripts added. 20 | - Optimized database storage (compressed). 21 | - Usage of adapted Doge node with improved API responses. 22 | - Adaptive gas price for submissions. 23 | - Configuration and deployment scripts updated. 24 | - Responses of web server and verification servers updated. 25 | - Logging messages updated. 26 | - Improved monitoring code. 27 | - Test coverage improved. 28 | -------------------------------------------------------------------------------- /config.modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Important: no spaces before and after = sign! 4 | 5 | # Set your hostname 6 | # This cannot be changed later (easily). 7 | # Do not use backslash at end !!! 8 | export HOSTNAME=www.yourhostname.com 9 | 10 | # Set your email for certificate expiration notification 11 | # This cannot be changed later (easily). 12 | export CERT_EMAIL=spam@google.com 13 | 14 | # set true or false for modules to be installed (NO SPACES before and after = sign!) 15 | 16 | # prerequisits 17 | export INSTALL_MYSQL=true 18 | 19 | # services 20 | export INSTALL_INDEXER=true 21 | export INSTALL_VERIFIER=true 22 | export INSTALL_MONITOR=true 23 | export INSTALL_FRONTEND=false 24 | 25 | # nodes 26 | export INSTALL_NODES_TESTNET=true 27 | 28 | # not supported yet 29 | export INSTALL_NODES_MAINNET=false 30 | 31 | # attestation client 32 | export INSTALL_FLARE=false 33 | export INSTALL_SONGBIRD=false 34 | export INSTALL_COSTON=false 35 | export INSTALL_COSTON2=true 36 | -------------------------------------------------------------------------------- /configs/.install/chain-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | // Bitcoin node credentials 3 | "BTCURL":"http://bitcoin-node:8332", 4 | "BTCUsername":"admin", 5 | "BTCPassword":"$(GENERATE_RANDOM_PASSWORD_64)", 6 | 7 | // Ripple node credentials 8 | "XRLURL":"http://ripple-node:51234", 9 | "XRPUsername":"", 10 | "XRPPassword":"", 11 | 12 | // Dogecoin node credentials 13 | "DOGEURL":"http://dogecoin-node:22555", 14 | "DOGEUsername":"admin", 15 | "DOGEPassword":"$(GENERATE_RANDOM_PASSWORD_64)" 16 | } 17 | -------------------------------------------------------------------------------- /configs/.install/install-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "Hostname":"$(HOSTNAME)", 3 | 4 | "FrontEndPort":3200, 5 | } -------------------------------------------------------------------------------- /configs/.install/monitor-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "Monitor.XRLURL":"http://localhost:51234", 3 | "Monitor.BTCURL":"http://localhost:8332", 4 | "Monitor.DOGEURL":"http://localhost:22555", 5 | 6 | "Monitor.BTCIndexerDatabaseHost" : "localhost", 7 | "Monitor.BTCIndexerDatabasePort": 23306, 8 | 9 | "Monitor.DOGEIndexerDatabaseHost" : "localhost", 10 | "Monitor.DOGEIndexerDatabasePort": 23307, 11 | 12 | "Monitor.XRPIndexerDatabaseHost" : "localhost", 13 | "Monitor.XRPIndexerDatabasePort": 23308, 14 | 15 | "Monitor.AttesterDatabaseHost" : "localhost", 16 | "Monitor.AttesterDatabasePort": 13306, 17 | } 18 | -------------------------------------------------------------------------------- /configs/.install/spammer-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | // Spammer does not need to be configured in production. Used only for test purposes. 3 | "BTCSpammerPrivateKey":"", 4 | "DOGESpammerPrivateKey":"", 5 | "XRPSpammerPrivateKey":"", 6 | 7 | "BTCSpammerNodeURL": "", 8 | "BTCSpammerNodeUsername": "", 9 | "BTCSpammerNodePassword": "", 10 | 11 | "DOGESpammerNodeURL": "", 12 | "DOGESpammerNodeUsername": "", 13 | "DOGESpammerNodePassword": "" 14 | 15 | } -------------------------------------------------------------------------------- /configs/.install/templates/attester-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // epoch start time in unix time 3 | "firstEpochStartTime": 1636070400, 4 | // epoch duration in seconds 5 | "roundDurationSec": 90, 6 | // Global configurations folder 7 | "globalConfigurationsFolder": "./configs/global-configs/$(Network)/", 8 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 9 | "commitTimeSec": -10, 10 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 11 | "bitVoteTimeSec": -10, 12 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 13 | "forceCloseBitVotingSec": 10, 14 | "web": { 15 | "accountPrivateKey": "$(NetworkPrivateKey)", 16 | "rpcUrl": "$(RPC)", 17 | "stateConnectorContractAddress": "$(StateConnectorContractAddress)", 18 | "refreshEventsMs": $(RefreshEventsMs), 19 | "bitVotingContractAddress": "$(BitVotingContractAddress)", 20 | //"gasLimit": "2500000", 21 | //"gasPrice": "300000000000", 22 | }, 23 | "attesterDatabase": { 24 | "host": "$(AttesterDatabaseHost)", 25 | "port": $(AttesterDatabasePort), 26 | "database": "$(AttesterDatabase)", 27 | "username": "$(AttesterWriterUsername)", 28 | "password": "$(AttesterWriterPassword)" 29 | } 30 | } -------------------------------------------------------------------------------- /configs/.install/templates/spammer/btc-spammer-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // epoch start time in unix time 3 | "firstEpochStartTime": 1636070400, 4 | // epoch duration in seconds 5 | "roundDurationSec": 90, 6 | "numberOfConfirmations": 6, 7 | "web": { 8 | "accountPrivateKey": "$(BTCSpammerPrivateKey)", 9 | "rpcUrl": "$(RPC)", 10 | "stateConnectorContractAddress": "$(StateConnectorContractAddress)" 11 | }, 12 | "indexerDatabase": { 13 | "host": "$(BTCIndexerDatabaseHost)", 14 | "port": $(BTCIndexerDatabasePort), 15 | "database": "$(BTCIndexerDatabase)", 16 | "username": "$(BTCIndexerReaderUsername)", 17 | "password": "$(BTCIndexerReaderPassword)" 18 | }, 19 | // See documentation for class `ChainConfig` in `src/attester/configs` 20 | "chainConfiguration": { 21 | "name": "BTC", 22 | "mccCreate": { 23 | "url": "$(BTCSpammerNodeURL)", 24 | "username": "$(BTCSpammerNodeUsername)", 25 | "password": "$(BTCSpammerNodePassword)" 26 | }, 27 | "rateLimitOptions": { 28 | "maxRPS": 20, 29 | "timeoutMs": 15000, 30 | "retries": 3 31 | }, 32 | "numberOfConfirmations": 6, 33 | "syncReadAhead": 10, 34 | "blockCollecting": "tips", 35 | "minimalStorageHistoryDays": 2, 36 | "minimalStorageHistoryBlocks": 100, 37 | } 38 | } -------------------------------------------------------------------------------- /configs/.install/templates/spammer/doge-spammer-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // epoch start time in unix time 3 | "firstEpochStartTime": 1636070400, 4 | // epoch duration in seconds 5 | "roundDurationSec": 90, 6 | "numberOfConfirmations": 6, 7 | "web": { 8 | "accountPrivateKey": "$(DOGESpammerPrivateKey)", 9 | "rpcUrl": "$(RPC)", 10 | "stateConnectorContractAddress": "$(StateConnectorContractAddress)" 11 | }, 12 | "indexerDatabase": { 13 | "name": "", 14 | "host": "$(DOGEIndexerDatabaseHost)", 15 | "port": $(DOGEIndexerDatabasePort), 16 | "database": "$(DOGEIndexerDatabase)", 17 | "username": "$(DOGEIndexerReaderUsername)", 18 | "password": "$(DOGEIndexerReaderPassword)" 19 | }, 20 | // See documentation for class `ChainConfig` in `src/attester/configs` 21 | "chainConfiguration": { 22 | "name": "DOGE", 23 | "mccCreate": { 24 | "url": "$(DOGESpammerNodeURL)", 25 | "username": "$(DOGESpammerNodeUsername)", 26 | "password": "$(DOGESpammerNodePassword)" 27 | }, 28 | "rateLimitOptions": { 29 | "maxRPS": 30, 30 | "timeoutMs": 5000, 31 | "retries": 3 32 | }, 33 | "numberOfConfirmations": 6, 34 | "syncReadAhead": 10, 35 | "blockCollecting": "tips", 36 | "minimalStorageHistoryDays": 2, 37 | "minimalStorageHistoryBlocks": 100, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /configs/.install/templates/spammer/xrp-spammer-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // epoch start time in unix time 3 | "firstEpochStartTime": 1636070400, 4 | // epoch duration in seconds 5 | "roundDurationSec": 90, 6 | "numberOfConfirmations": 1, 7 | "web": { 8 | "accountPrivateKey": "$(XRPSpammerPrivateKey)", 9 | "rpcUrl": "$(RPC)", 10 | "stateConnectorContractAddress": "$(StateConnectorContractAddress)" 11 | }, 12 | "indexerDatabase": { 13 | "host": "$(XRPIndexerDatabaseHost)", 14 | "port": $(XRPIndexerDatabasePort), 15 | "database": "$(XRPIndexerDatabase)", 16 | "username": "$(XRPIndexerReaderUsername)", 17 | "password": "$(XRPIndexerReaderPassword)" 18 | } 19 | } -------------------------------------------------------------------------------- /configs/.install/templates/stats-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // stats update interval 3 | "interval":5000, 4 | // save stats path 5 | "path":"../stats/docker_stats.json", 6 | } -------------------------------------------------------------------------------- /configs/.install/templates/verifier-server/btc-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "$(BTCApiKey1)" 6 | } 7 | ], 8 | "port": $(BTCVerifierRouterServerPort), 9 | "checkAliveIntervalMs": 5000, 10 | "sourceId": "BTC", 11 | "attestationTypes": [ 12 | "Payment", 13 | "BalanceDecreasingTransaction", 14 | "ConfirmedBlockHeightExists", 15 | "ReferencedPaymentNonexistence" 16 | ], 17 | "indexerDatabase": { 18 | "host": "$(BTCIndexerDatabaseHost)", 19 | "port": $(BTCIndexerDatabasePort), 20 | "database": "$(BTCIndexerDatabase)", 21 | "username": "$(BTCIndexerReaderUsername)", 22 | "password": "$(BTCIndexerReaderPassword)" 23 | }, 24 | "chainConfiguration": { 25 | "name": "BTC", 26 | "mccCreate": { 27 | "url": "$(BTCURL)", 28 | "username": "$(BTCUsername)", 29 | "password": "$(BTCPassword)" 30 | }, 31 | "rateLimitOptions": { 32 | "maxRPS": 20, 33 | "timeoutMs": 15000, 34 | "retries": 3 35 | }, 36 | "numberOfConfirmations": 6, 37 | "syncReadAhead": 10, 38 | "blockCollecting": "tips", 39 | "minimalStorageHistoryDays": 2, 40 | "minimalStorageHistoryBlocks": 100, 41 | } 42 | } -------------------------------------------------------------------------------- /configs/.install/templates/verifier-server/doge-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "$(DOGEApiKey1)" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "$(DOGEApiKey1)" 10 | } 11 | ], 12 | "port": $(DOGEVerifierRouterServerPort), 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "DOGE", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction", 18 | "ConfirmedBlockHeightExists", 19 | "ReferencedPaymentNonexistence" 20 | ], 21 | "indexerDatabase": { 22 | "name": "", 23 | "host": "$(DOGEIndexerDatabaseHost)", 24 | "port": $(DOGEIndexerDatabasePort), 25 | "database": "$(DOGEIndexerDatabase)", 26 | "username": "$(DOGEIndexerReaderUsername)", 27 | "password": "$(DOGEIndexerReaderPassword)" 28 | }, 29 | "chainConfiguration": { 30 | "name": "DOGE", 31 | "mccCreate": { 32 | "url": "$(DOGEURL)", 33 | "username": "$(DOGEUsername)", 34 | "password": "$(DOGEPassword)" 35 | }, 36 | "rateLimitOptions": { 37 | "maxRPS": 30, 38 | "timeoutMs": 5000, 39 | "retries": 3 40 | }, 41 | "numberOfConfirmations": 60, 42 | "syncReadAhead": 10, 43 | "blockCollecting": "tips", 44 | "minimalStorageHistoryDays": 2, 45 | "minimalStorageHistoryBlocks": 100, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /configs/.install/templates/verifier-server/xrp-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "$(XRPApiKey1)" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "$(XRPApiKey1)" 10 | } 11 | ], 12 | "port": $(XRPVerifierRouterServerPort), 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "XRP", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction", 18 | "ConfirmedBlockHeightExists", 19 | "ReferencedPaymentNonexistence" 20 | ], 21 | "indexerDatabase": { 22 | "host": "$(XRPIndexerDatabaseHost)", 23 | "port": $(XRPIndexerDatabasePort), 24 | "database": "$(XRPIndexerDatabase)", 25 | "username": "$(XRPIndexerReaderUsername)", 26 | "password": "$(XRPIndexerReaderPassword)" 27 | }, 28 | "chainConfiguration": { 29 | // chain name. allowed names are XRP, BTC, LTC, ALGO, DOGE 30 | "name": "XRP", 31 | // MCC create options 32 | "mccCreate": { 33 | "url": "$(XRLURL)", 34 | "username": "", 35 | "password": "", 36 | }, 37 | // rate limiting options 38 | "rateLimitOptions": { 39 | "maxRPS": 20, 40 | "timeoutMs": 30000, 41 | "retries": 10 42 | }, 43 | "numberOfConfirmations": 1, 44 | "syncReadAhead": 20, 45 | "blockCollecting": "raw", 46 | "minimalStorageHistoryDays": 2, 47 | "minimalStorageHistoryBlocks": 100, 48 | } 49 | } -------------------------------------------------------------------------------- /configs/.install/templates/webserver-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstEpochStartTime":1636070400, 3 | "roundDurationSec": 90, 4 | "serviceStatusFilePath": "../monitor-status.json", 5 | 6 | "port": $(WebserverPort), 7 | 8 | "attesterDatabase": { 9 | "host": "$(AttesterDatabaseHost)", 10 | "port": $(AttesterDatabasePort), 11 | "database": "$(AttesterDatabase)", 12 | "username": "$(AttesterReaderUsername)", 13 | "password": "$(AttesterReaderPassword)" 14 | }, 15 | } -------------------------------------------------------------------------------- /configs/.install/verifier-client-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | // NOTE: For docker deploy on the same machine the paths in the route are 3 | // already correctly configured. The value of `localhost` should be replaced 4 | // by the external IP of the machine on which docker containers are running. 5 | 6 | // Bitcoin verifier URL and API key 7 | "BTCVerifierRouterClientUrl": "http://localhost:9500/verifier/btc", 8 | "BTCVerifierRouterClientApiKey": "$(BTCApiKey1)", 9 | 10 | // Dogecoin verifier URL and API key 11 | "DOGEVerifierRouterClientUrl": "http://localhost:9504/verifier/doge", 12 | "DOGEVerifierRouterClientApiKey": "$(DOGEApiKey1)", 13 | 14 | // XRP verifier URL and API key 15 | "XRPVerifierRouterClientUrl": "http://localhost:9501/verifier/xrp", 16 | "XRPVerifierRouterClientApiKey": "$(XRPApiKey1)", 17 | 18 | // ETH verifier URL and API key 19 | "ETHVerifierRouterClientUrl": "http://localhost:9501/verifier/eth", 20 | "ETHVerifierRouterClientApiKey": "$(EVMApiKey1)", 21 | 22 | // FLR verifier URL and API key 23 | "FLRVerifierRouterClientUrl": "http://localhost:9501/verifier/flr", 24 | "FLRVerifierRouterClientApiKey": "$(EVMApiKey1)" 25 | } -------------------------------------------------------------------------------- /configs/.install/verifier-server-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | // Ports for running verifier server. 3 | // NOTE: In docker deployment all those ports should remain 9500 4 | "BTCVerifierRouterServerPort": "9500", 5 | "XRPVerifierRouterServerPort": "9500", 6 | "DOGEVerifierRouterServerPort": "9500", 7 | 8 | // API Keys for verifier servers. 9 | // If more keys are to be added, add more unique stub entries here and more entries in 10 | // `credentials.prepared/-indexer-verifier/templates/verifier-server/-verifier-config.json` 11 | "BTCApiKey1":"$(GENERATE_RANDOM_PASSWORD_16)", 12 | "DOGEApiKey1":"$(GENERATE_RANDOM_PASSWORD_16)", 13 | "XRPApiKey1":"$(GENERATE_RANDOM_PASSWORD_16)", 14 | 15 | } -------------------------------------------------------------------------------- /configs/.install/webserver-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | // Attestation client web serve port 3 | // For docker deployment this port should remain 3000. 4 | // External docker ports should be set in docker-compose yaml files during the deployment. 5 | "WebserverPort":3000, 6 | } -------------------------------------------------------------------------------- /configs/global-configs/coston/global-0-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 0, 3 | // Coston assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x30e4b4542b4aAf615838B113f14c46dE1469212e", 6 | "0x3519E14183252794aaA52aA824f34482ef44cE1d", 7 | "0xb445857476181ec378Ec453ab3d122183CfC3b78", 8 | "0x6D755cd7A61A9DCFc96FaE0f927C3a73bE986ce4", 9 | "0xdC0fD24846303D58d2D66AA8820be2685735dBd2", 10 | "0x3F52c41c0500a4f018A38c9f8273b254aD7e2FCc", 11 | "0xdA6d6aA9F1f770c279c5DA0C71f4DC1142A70d5D", 12 | "0x3d895D00d2802120D39d4D2554F7ef09d6845E99", 13 | "0xc36141CFBe5Af6eB2F8b21550Ccd457DA7FaF3C6" 14 | ] 15 | } -------------------------------------------------------------------------------- /configs/global-configs/coston/global-150-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 150, 3 | // Coston assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x30e4b4542b4aAf615838B113f14c46dE1469212e", 6 | "0x3519E14183252794aaA52aA824f34482ef44cE1d", 7 | "0xb445857476181ec378Ec453ab3d122183CfC3b78", 8 | "0x6D755cd7A61A9DCFc96FaE0f927C3a73bE986ce4", 9 | "0xdC0fD24846303D58d2D66AA8820be2685735dBd2", 10 | "0x3F52c41c0500a4f018A38c9f8273b254aD7e2FCc", 11 | "0xdA6d6aA9F1f770c279c5DA0C71f4DC1142A70d5D", 12 | "0x3d895D00d2802120D39d4D2554F7ef09d6845E99", 13 | "0xc36141CFBe5Af6eB2F8b21550Ccd457DA7FaF3C6" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /configs/global-configs/coston2/global-0-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 0, 3 | // Coston2 assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x30e4b4542b4aAf615838B113f14c46dE1469212e", 6 | "0x3519E14183252794aaA52aA824f34482ef44cE1d", 7 | "0xb445857476181ec378Ec453ab3d122183CfC3b78", 8 | "0x6D755cd7A61A9DCFc96FaE0f927C3a73bE986ce4", 9 | "0xdC0fD24846303D58d2D66AA8820be2685735dBd2", 10 | "0x3F52c41c0500a4f018A38c9f8273b254aD7e2FCc", 11 | "0xdA6d6aA9F1f770c279c5DA0C71f4DC1142A70d5D", 12 | "0x3d895D00d2802120D39d4D2554F7ef09d6845E99", 13 | "0xc36141CFBe5Af6eB2F8b21550Ccd457DA7FaF3C6" 14 | ] 15 | } -------------------------------------------------------------------------------- /configs/global-configs/coston2/global-150-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 150, 3 | // Coston2 assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x30e4b4542b4aAf615838B113f14c46dE1469212e", 6 | "0x3519E14183252794aaA52aA824f34482ef44cE1d", 7 | "0xb445857476181ec378Ec453ab3d122183CfC3b78", 8 | "0x6D755cd7A61A9DCFc96FaE0f927C3a73bE986ce4", 9 | "0xdC0fD24846303D58d2D66AA8820be2685735dBd2", 10 | "0x3F52c41c0500a4f018A38c9f8273b254aD7e2FCc", 11 | "0xdA6d6aA9F1f770c279c5DA0C71f4DC1142A70d5D", 12 | "0x3d895D00d2802120D39d4D2554F7ef09d6845E99", 13 | "0xc36141CFBe5Af6eB2F8b21550Ccd457DA7FaF3C6" 14 | ] 15 | } -------------------------------------------------------------------------------- /configs/global-configs/flare/global-0-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 0, 3 | // Flare assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x0988Cf4828F4e4eD0cE7c07467E70e19095Ee152", 6 | "0x6BC7DCa62010D418eB72CCdc58561e00C5868Ef1", 7 | "0xE34Bb361536610a9DCcEa5292262e36AfF65c06c", 8 | "0x8A3D627D86A81F5D21683F4963565C63DB5e1309", 9 | "0x2D3e7e4b19bDc920fd9C57BD3072A31F5a59FeC8", 10 | "0x6455dC38fdF739b6fE021b30C7D9672C1c6DEb5c", 11 | "0x49893c5Dfc035F4eE4E46faC014f6D4bC80F7f92", 12 | "0x08e8b2Af4874e920de27723576A13d66008Af523", 13 | "0x5D2f75392DdDa69a2818021dd6a64937904c8352" 14 | ] 15 | } -------------------------------------------------------------------------------- /configs/global-configs/flare/global-150-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 150, 3 | // Flare assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x0988Cf4828F4e4eD0cE7c07467E70e19095Ee152", 6 | "0x6BC7DCa62010D418eB72CCdc58561e00C5868Ef1", 7 | "0xE34Bb361536610a9DCcEa5292262e36AfF65c06c", 8 | "0x8A3D627D86A81F5D21683F4963565C63DB5e1309", 9 | "0x2D3e7e4b19bDc920fd9C57BD3072A31F5a59FeC8", 10 | "0x6455dC38fdF739b6fE021b30C7D9672C1c6DEb5c", 11 | "0x49893c5Dfc035F4eE4E46faC014f6D4bC80F7f92", 12 | "0x08e8b2Af4874e920de27723576A13d66008Af523", 13 | "0x5D2f75392DdDa69a2818021dd6a64937904c8352" 14 | ] 15 | } -------------------------------------------------------------------------------- /configs/global-configs/songbird/global-0-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 0, 3 | // Songbird assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0x442DD539Fe78D43A1a9358FF3460CfE63e2bC9CC", 6 | "0x49893c5Dfc035F4eE4E46faC014f6D4bC80F7f92", 7 | "0x85016969b9eBDB8977975a4743c9FCEeabCEAf8A", 8 | "0x8A3D627D86A81F5D21683F4963565C63DB5e1309", 9 | "0x823B0f5c7758E9d3bE55bA1EA840E29ccd5D5CcB", 10 | "0x808441Ec3Fa1721330226E69527Bc160D8d9386a", 11 | "0x6455dC38fdF739b6fE021b30C7D9672C1c6DEb5c", 12 | "0x2D3e7e4b19bDc920fd9C57BD3072A31F5a59FeC8", 13 | "0x5D2f75392DdDa69a2818021dd6a64937904c8352" 14 | ] 15 | } -------------------------------------------------------------------------------- /configs/global-configs/songbird/global-150-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 150, 3 | // Songbird assigners 4 | "defaultSetAssignerAddresses": [ 5 | "0xcE397b9a395ace2e328030699bDDf4E2F049A05B", 6 | "0xeDBb013BBC314124a9f842c1887e34cfeB03B052", 7 | "0xb9eF3951ac2D04C6bdD886bF042041E3954E86aF", 8 | "0x816Cec8f3A37Fd673Cfd4229441c59cA8DbD0641", 9 | "0x14c9c4583F0b1af8a69452Ec1b29884240f83bDC", 10 | "0x0049081C2D6def64800cC011Bd9aDe8682c6593a", 11 | "0x53Fcb50a22aFd6e5438d754CB22c4726032d2488", 12 | "0x35f4F0Bb73a6040F24927e1735B089d7769F7674", 13 | "0x3B583C919fD4C863F3A17d11929346C687FfB7c3" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /contracts/Merkle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.11; 3 | 4 | import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; 5 | 6 | contract Merkle { 7 | using MerkleProof for bytes32[]; 8 | 9 | function verifyMerkleProof( 10 | bytes32[] calldata proof, 11 | bytes32 merkleRoot, 12 | bytes32 leaf 13 | ) external pure returns (bool) { 14 | return proof.verify(merkleRoot, leaf); 15 | } 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /contracts/generated/contracts/SCProofVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.11; 3 | 4 | import "./SCProofVerifierBase.sol"; 5 | import "../interface/IStateConnector.sol"; 6 | 7 | contract SCProofVerifier is SCProofVerifierBase { 8 | IStateConnector public stateConnector; 9 | 10 | constructor(IStateConnector _stateConnector) { 11 | stateConnector = _stateConnector; 12 | } 13 | 14 | function merkleRootForRound(uint256 _stateConnectorRound) public view override returns (bytes32 _merkleRoot) { 15 | return stateConnector.merkleRoot(_stateConnectorRound); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/generated/contracts/SCProofVerifierMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.11; 3 | 4 | import "./SCProofVerifierBase.sol"; 5 | 6 | 7 | contract SCProofVerifierMock is SCProofVerifierBase { 8 | 9 | uint256 public constant BUFFER_WINDOW = 90 seconds; 10 | uint256 public constant TOTAL_STORED_PROOFS = (1 weeks)/BUFFER_WINDOW; 11 | 12 | bytes32[TOTAL_STORED_PROOFS] public merkleRoots; 13 | 14 | function setMerkleRoot(uint256 _stateConnectorRound, bytes32 _merkleRoot) external { 15 | merkleRoots[_stateConnectorRound % TOTAL_STORED_PROOFS] = _merkleRoot; 16 | } 17 | 18 | function merkleRootForRound(uint256 _stateConnectorRound) public view override returns (bytes32 _merkleRoot) { 19 | return merkleRoots[_stateConnectorRound % TOTAL_STORED_PROOFS]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/generated/contracts/StateConnectorMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.11; 3 | 4 | import "../interface/IStateConnector.sol"; 5 | 6 | contract StateConnectorMock is IStateConnector { 7 | uint256 public constant BUFFER_WINDOW = 90 seconds; 8 | uint256 public constant TOTAL_STORED_PROOFS = (1 weeks)/BUFFER_WINDOW; 9 | uint256 public constant BUFFER_TIMESTAMP_OFFSET = 1636070400 seconds; 10 | 11 | bytes32[TOTAL_STORED_PROOFS] public merkleRoots; 12 | uint256 public lastFinalizedRoundId = 0; 13 | 14 | function setMerkleRoot(uint256 _stateConnectorRound, bytes32 _merkleRoot) external { 15 | merkleRoots[_stateConnectorRound % TOTAL_STORED_PROOFS] = _merkleRoot; 16 | lastFinalizedRoundId = _stateConnectorRound; 17 | emit RoundFinalised(_stateConnectorRound, _merkleRoot); 18 | } 19 | 20 | function requestAttestations(bytes calldata _data) external { 21 | emit AttestationRequest(msg.sender, block.timestamp, _data); 22 | } 23 | 24 | function merkleRoot(uint256 _roundId) external view returns (bytes32) { 25 | require(_roundId <= lastFinalizedRoundId, "not finalized"); 26 | require(_roundId + TOTAL_STORED_PROOFS > lastFinalizedRoundId, "expired"); 27 | return merkleRoots[_roundId % TOTAL_STORED_PROOFS]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/generated/interface/IStateConnector.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.6 <0.9; 3 | 4 | // solhint-disable func-name-mixedcase 5 | interface IStateConnector { 6 | event AttestationRequest( 7 | address sender, 8 | uint256 timestamp, 9 | bytes data 10 | ); 11 | 12 | event RoundFinalised( 13 | uint256 indexed roundId, 14 | bytes32 merkleRoot 15 | ); 16 | 17 | /** 18 | * The method to call for requesting a new attestation. 19 | * Emits event `AttestationRequest`, which triggers work by attestation providers. 20 | */ 21 | function requestAttestations(bytes calldata _data) external; 22 | 23 | /** 24 | * Last finalized round id. 25 | */ 26 | function lastFinalizedRoundId() external view returns (uint256 _roundId); 27 | 28 | /** 29 | * Get Merkle root for the round and check for buffer overflows. 30 | */ 31 | function merkleRoot(uint256 _roundId) external view returns (bytes32); 32 | 33 | /** 34 | * The first buffer timestamp 35 | * (start time in seconds for converting the timestamp into a round number). 36 | */ 37 | function BUFFER_TIMESTAMP_OFFSET() external view returns (uint256); 38 | 39 | /** 40 | * Amount of time a buffer is active before cycling to the next one 41 | * (round length in seconds for converting the timestamp into a round number). 42 | */ 43 | function BUFFER_WINDOW() external view returns (uint256); 44 | } 45 | -------------------------------------------------------------------------------- /contracts/scripts/flatten-fix.ts: -------------------------------------------------------------------------------- 1 | function fixFlatten() { 2 | const fs = require("fs"); 3 | console.log(process.argv[2]); 4 | const data = String(fs.readFileSync(process.argv[2])); 5 | const ind = data.indexOf("SPDX-License-Identifier: MIT", 0); 6 | const beg = data.slice(0, ind + 5); 7 | const end = data.slice(ind + 5, data.length).replace(/SPDX-License-Identifier: MIT/g, ""); 8 | const outData = beg + end; 9 | let j = outData.length + 1; 10 | let ncnt = 0; 11 | while (ncnt < 2) { 12 | if (outData[j] == "\n") ncnt++; 13 | j--; 14 | } 15 | let i = 0; 16 | ncnt = 0; 17 | while (ncnt < 2) { 18 | if (outData[i] == "\n") ncnt++; 19 | i++; 20 | } 21 | fs.writeFileSync(process.argv[2], outData.slice(i, j + 1), "utf8"); 22 | } 23 | 24 | fixFlatten(); 25 | -------------------------------------------------------------------------------- /contracts/scripts/flatten.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo $1 4 | mkdir -p flattened/$(dirname "$1") 5 | yarn hardhat flatten $1 > flattened/$1 6 | yarn ts-node contracts/scripts/flatten-fix.ts flattened/$1 7 | -------------------------------------------------------------------------------- /devdocs.md: -------------------------------------------------------------------------------- 1 | # For testing 2 | 3 | ``` 4 | yarn 5 | yarn c 6 | ``` 7 | 8 | Classic unit tests: 9 | ``` 10 | yarn test-all-fast 11 | ``` 12 | 13 | End to end testing 14 | ``` 15 | yarn test_endtoend 16 | ``` 17 | 18 | # Mock databases 19 | 20 | End-to-ebd testing uses mock databases 21 | 22 | the files are located in `test/indexed-query-manager/test-data` 23 | 24 | those files should always reflect the raw responses that node makes when requesting the transaction or block data. 25 | -------------------------------------------------------------------------------- /docker/scripts/attestation-client: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/runAttestationClient.js 4 | -------------------------------------------------------------------------------- /docker/scripts/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | -------------------------------------------------------------------------------- /docker/scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec "$@" 4 | -------------------------------------------------------------------------------- /docker/scripts/indexer: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/runIndexer.js -a "$1" 4 | -------------------------------------------------------------------------------- /docker/scripts/monitor: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/runMonitor.js 4 | -------------------------------------------------------------------------------- /docker/scripts/spammer: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/spammer/attestation-spammer.js -c "$1" -d "$2" 4 | -------------------------------------------------------------------------------- /docker/scripts/stats: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/runDockerStats.js 4 | -------------------------------------------------------------------------------- /docker/scripts/verification-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/servers/verifier-server/main.js 4 | -------------------------------------------------------------------------------- /docker/scripts/webserver: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec node dist/src/servers/web-server/main.js 4 | -------------------------------------------------------------------------------- /docs/attestation-client/attestation-suite.md: -------------------------------------------------------------------------------- 1 | # Attestation suite 2 | 3 | Attestation suite is the set of services that allow attestation providers to participate in the attestation protocol. 4 | On a high level in includes: 5 | 6 | - [Attestation client](./attestation-client.md) - monitors a Flare blockchain for attestation requests, forwards requests to verification servers, collect the verifications/rejections, prepares votes for each voting round and votes. 7 | - Verifiers - a verifier is deployed as an API server per data source (e.g. blockchain) and are in charge for verification of specific attestation requests. A verifier has access to an indexer database that is used to carry out queries needed to verify attestation requests. An important part of the verifier server is the 8 | verification code, which performs relevant queries to the indexer database and carries out relevant checks, as required by a specific attestation type. 9 | - [Indexers](../indexing/indexer.md) - an indexer reads blockchain nodes (or a data source in general) and prepares a queryable database, subject to limitations, that are relevant for specific attestation types (e.g. all indexed transactions in the database have a sufficient number of confirmations). Indexers typically use interfacing library to read from a blockchain node (e.g. [Multi Chain Client](https://github.com/flare-foundation/multi-chain-client)). 10 | - [Blockchain nodes](./blockchain-nodes.md) - block chain nodes. 11 | 12 | Next: [Attestation Client](./attestation-client.md) 13 | 14 | [Back to home](../README.md) 15 | -------------------------------------------------------------------------------- /docs/attestation-client/blockchain-nodes.md: -------------------------------------------------------------------------------- 1 | # Blockchain nodes 2 | 3 | Blockchain nodes that attestation protocol currently support are 4 | 5 | - Bitcoin 6 | - Dogecoin 7 | - XRPL (limited history) 8 | 9 | The latest docker images are defined in the [Connected Chains Docker repo](https://github.com/flare-foundation/connected-chains-docker) and are published on [Dockerhub](https://hub.docker.com/u/flarefoundation) 10 | 11 | [Back to home](../README.md) 12 | -------------------------------------------------------------------------------- /docs/config/json/json-DatabaseConfiguration.md: -------------------------------------------------------------------------------- 1 | # Database Configuration 2 | 3 | | Name | Description | Default | 4 | | ---------- | -------------------------------------------------------------------------------- | ----------- | 5 | | `type` | Server database type.
Supported database types "mysql", "postgres", "sqlite" | "mysql" | 6 | | `host` | Server address | "localhost" | 7 | | `port` | Server port number.
default is for `mysql` | 3306 | 8 | | `database` | Database name | | 9 | | `username` | Database username | | 10 | | `password` | Database password | | 11 | 12 | > **NOTE:** 13 | > Entries with default values are optional. 14 | -------------------------------------------------------------------------------- /docs/config/json/json-MCCCreateConfiguration.md: -------------------------------------------------------------------------------- 1 | # MCC Create Configuration 2 | 3 | MCC Create Configuration depends on the selected chain. 4 | 5 | ## XRP chain MCC Create Configuration 6 | 7 | > Class `XrpMccCreate` 8 | 9 | | Name | Description | Default | 10 | | ----------- | ---------------- | ------- | 11 | | `url` | XRP RPC address | | 12 | | `username` | Network username | "" | 13 | | `password` | Network password | "" | 14 | | `inRegTest` | | false | 15 | 16 | ## UTXO chain MCC Create Configuration 17 | 18 | > Class `UtxoMccCreate` 19 | 20 | | Name | Description | Default | 21 | | ----------- | ---------------- | ------- | 22 | | `url` | XRP RPC address | | 23 | | `username` | Network username | "" | 24 | | `password` | Network password | "" | 25 | | `inRegTest` | | false | 26 | 27 | > **NOTE:** 28 | > Entries with default values are optional. 29 | -------------------------------------------------------------------------------- /docs/config/json/json-NetworkConfiguration.md: -------------------------------------------------------------------------------- 1 | # Network Configuration 2 | 3 | | Name | Description | Default | 4 | | ------------------------------- | --------------------------------------------------------------------------------------- | ------- | 5 | | `accountPrivateKey` | Network account private key.
**IMPORTANT** for Attester this account must be funded | | 6 | | `rpcUrl` | Network RPC URL | | 7 | | `stateConnectorContractAddress` | State connector address | | 8 | | `refreshEventsMs` | Event collecting polling sleep delay | 100 | 9 | 10 | 11 | Available State Connector contract addresses: 12 | 13 | - `0x1000000000000000000000000000000000000001` for Flare 14 | - `0x3A1b3220527aBA427d1e13e4b4c48c31460B4d91` for Songbird 15 | - `0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F` for Coston 16 | - `0x1000000000000000000000000000000000000001` for Coston2 17 | 18 | > Values with default value are optional. 19 | -------------------------------------------------------------------------------- /docs/config/json/json-RateLimitingOptions.md: -------------------------------------------------------------------------------- 1 | # Rate Limiting Options 2 | 3 | | Name | Description | Default | 4 | | ----------- | ---------------------------------------- | ------- | 5 | | `maxRPS` | Maximum requests per second | 20 | 6 | | `timeoutMs` | Request timeout | 30000 | 7 | | `retries` | Number of request retries before failing | 10 | 8 | 9 | > **NOTE:** 10 | > Entries with default values are optional. 11 | -------------------------------------------------------------------------------- /docs/indexing/indexer.md: -------------------------------------------------------------------------------- 1 | # Blockchain indexer 2 | 3 | The main data structure of blockchains typically consists of a sequence of blocks, where each block contains transactions in a specific order. 4 | Each block is identified by a block hash and has a specific block number (height). Each transaction is identified by a transaction id (hash). Blockchain nodes have APIs that allow reading blocks and transactions. An indexer is used to collect the data about the blocks and transactions for a certain period and enable users to make certain types of queries fast. For our use with attestation providers, indexers are used to read transactions within a certain **indexing time window** from the present, back to some time in the past. For example for the last two days (duration `IndexingWindowSec`). 5 | 6 | Next: [Scope of indexing](./indexer-scope.md) 7 | 8 | [Back to Home](../README.md) 9 | -------------------------------------------------------------------------------- /docs/misc/indexer-algo-db-clone.md: -------------------------------------------------------------------------------- 1 | 2 | Disable service 3 | ``` 4 | nano ~/.config/systemd/user/indexer-algo.service 5 | 6 | 7 | systemctl --user daemon-reload 8 | systemctl --user restart indexer-algo 9 | systemctl --user status indexer-algo 10 | 11 | ``` 12 | 13 | 14 | 15 | ``` 16 | sudo mysql 17 | 18 | use indexer; 19 | drop tables algo_block, algo_transactions0, algo_transactions1; 20 | delete from state where name like 'ALGO%'; 21 | 22 | ``` 23 | 24 | ``` 25 | 26 | sudo mysqldump indexer state --where "name like '%ALGO%'" | xz | pv -W | ssh ubuntu@144.76.253.232 -i ~/.ssh/id_rsa "tee remote-dump.sql.xz | unxz | mysql -u indexerWriter -pPASSWORD indexer" 27 | 28 | sudo mysqldump indexer algo_block algo_transactions0 algo_transactions1 | xz | pv -W | ssh ubuntu@144.76.253.232 -i ~/.ssh/id_rsa "tee remote-dump.sql.xz | unxz | mysql -u indexerWriter -pPASSWORD indexer" 29 | 30 | ``` -------------------------------------------------------------------------------- /docs/misc/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | We test attestation client on multiple levels split intu multiple sections. 4 | 5 | All of the scripts associated with testing are collected in `-------TESTS---------` section in package.json. 6 | 7 | - Some tests are run in hardhat environment to test smart contracts and their interaction with network (`.test-contract.ts`) 8 | - Others are run with mocha. They are split into three groups: regular tests (`.test.ts`), slower tests (`.test-slow.ts`) and tests that need some additional credentials(`.test-cred.ts`). 9 | 10 | ## Tooling 11 | 12 | - [mocha](https://github.com/mochajs/mocha) 13 | - [hardhat](https://github.com/NomicFoundation/hardhat) 14 | - [sinon](https://github.com/sinonjs/sinon) 15 | - [chai](https://github.com/chaijs/chai) 16 | - [chai-as-promised](https://github.com/domenic/chai-as-promised) 17 | 18 | ## Coverage 19 | 20 | run 21 | 22 | Run all fast tests 23 | 24 | ```bash 25 | yarn test:coverage 26 | ``` 27 | 28 | Run all tests except the tests that need api credentials 29 | 30 | ```bash 31 | yarn test:coverage-full 32 | ``` 33 | 34 | Run all tests including the tests that need api credentials that need to be provided 35 | 36 | ```bash 37 | yarn test:coverage-fullc 38 | ``` 39 | 40 | ## Setting up testing environment 41 | 42 | [Back to home](../README.md) 43 | -------------------------------------------------------------------------------- /docs/misc/update-flare-node.md: -------------------------------------------------------------------------------- 1 | Flare Node Update script 2 | 3 | ``` 4 | bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) 5 | sudo apt -y install gcc g++ curl jq 6 | sudo apt-get install bison -y 7 | sudo apt-get install make -y 8 | sudo apt-get install golang-go -y 9 | sudo npm install gvm -y 10 | source ~/.profile 11 | 12 | gvm install go1.18.5 13 | gvm use go1.18.5 --default 14 | 15 | 16 | 17 | ``` 18 | 19 | ``` 20 | cd flare2/go-flare 21 | ``` 22 | 23 | Run from folder where you have avalanche git: 24 | 25 | ``` 26 | gvm install go1.18.5 27 | gvm use go1.18.5 --default 28 | git pull 29 | git checkout v0.7.1 30 | 31 | cd avalanchego/ 32 | ./scripts/build.sh 33 | 34 | cd .. 35 | 36 | ps -e | grep avalanche 37 | kill -2 $(ps -e | grep avalanche | awk '{print $1;}') 38 | 39 | mv build build.old 40 | mv avalanchego/build . 41 | 42 | ./flare.sh 43 | ``` 44 | 45 | Observe ... it takes few min to get 1st response :( 46 | 47 | ``` 48 | tail -f logs/flare/node1/main.log 49 | ``` 50 | 51 | Check what version you have (when it is running) 52 | 53 | ``` 54 | cat flare2/go-flare/logs/flare/node1/main.log | grep "node version is" 55 | ``` 56 | 57 | Update 58 | 59 | ``` 60 | gvm use go1.18.5 61 | git pull 62 | git checkout v1.7.1803 63 | 64 | cd avalanchego/ 65 | ./scripts/build.sh 66 | 67 | cd .. 68 | 69 | ps -e | grep avalanche 70 | kill -2 $(ps -e | grep avalanche | awk '{print $1;}') 71 | 72 | mv build build.old 73 | mv avalanchego/build . 74 | 75 | ./flare.sh 76 | ``` 77 | -------------------------------------------------------------------------------- /docs/misc/update-songbird-node.md: -------------------------------------------------------------------------------- 1 | Flare Node Update script 2 | 3 | ``` 4 | cd flare/flare 5 | ``` 6 | 7 | Run from folder where you have avalanche git: 8 | 9 | ``` 10 | gvm use go1.17.7 11 | git pull 12 | git checkout v0.6.4 13 | 14 | ps -e | grep flare 15 | 16 | kill -2 $(ps -e | grep flare | awk '{print $1;}') 17 | 18 | cd avalanchego/ 19 | ./scripts/build.sh 20 | 21 | cd .. 22 | mkdir chain-config/C 23 | cp chain-config/songbird.json chain-config/C/ 24 | 25 | mv build build.old 26 | mv avalanchego/build . 27 | 28 | ./songbird.sh 29 | ``` 30 | 31 | Observe ... it takes few min to get 1st response :( 32 | 33 | ``` 34 | tail -f logs/songbird/node1/main.log 35 | ``` 36 | 37 | Check what version you have (when it is running) 38 | 39 | ``` 40 | cat flare/flare/logs/songbird/node1/main.log | grep "node version is" 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/node/docker.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | ## Replace docker 4 | 5 | ## Remove docker 6 | 7 | Get container ID 8 | 9 | ``` bash 10 | sudo docker ps 11 | ``` 12 | 13 | Remove container 14 | 15 | ``` bash 16 | sudo docker stop 17 | sudo docker rm 18 | ``` 19 | 20 | Get Volume 21 | ``` bash 22 | sudo docker volume list 23 | ``` 24 | 25 | Remove volume 26 | ``` bash 27 | sudo docker volume rm 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /scripts/compile.sh: -------------------------------------------------------------------------------- 1 | export CURRENT_DIR=$(pwd) 2 | 3 | rm -rf node_modules 4 | 5 | rm -rf typechain-truffle 6 | rm -rf typechain-web3-v1 7 | rm -rf artifacts 8 | 9 | yarn install --frozen-lockfile 10 | 11 | # hardhat 12 | yarn c 13 | 14 | # main build 15 | yarn build -------------------------------------------------------------------------------- /scripts/direct-install/files/frontend.env: -------------------------------------------------------------------------------- 1 | # Coston 2 | COSTON_ATTESTER_BASE_URL=https://$(HOSTNAME)/coston/api/ 3 | COSTON_STATE_CONNECTOR_ADDRESS=0x947c76694491d3fD67a73688003c4d36C8780A97 4 | COSTON_ATTESTATION_CLIENT_ADDRESS=0xFdd0daaC0dc2eb8bD35eBdD8611d5322281fC527 5 | 6 | # Songbird 7 | SONGBIRD_ATTESTER_BASE_URL=https://$(HOSTNAME)/songbird/api/ 8 | SONGBIRD_STATE_CONNECTOR_ADDRESS=0x000000000000000000000000000000000000dEaD 9 | SONGBIRD_ATTESTATION_CLIENT_ADDRESS=0x000000000000000000000000000000000000dEaD 10 | 11 | # Coston 2 12 | COSTON2_ATTESTER_BASE_URL=https://$(HOSTNAME)/coston2/api/ 13 | COSTON2_STATE_CONNECTOR_ADDRESS=0x1000000000000000000000000000000000000001 14 | COSTON2_ATTESTATION_CLIENT_ADDRESS=0x000000000000000000000000000000000000dEaD 15 | 16 | # FLARE 17 | FLARE_ATTESTER_BASE_URL=https://$(HOSTNAME)/flare/api/ 18 | FLARE_STATE_CONNECTOR_ADDRESS=0x1000000000000000000000000000000000000001 19 | FLARE_ATTESTATION_CLIENT_ADDRESS=0x000000000000000000000000000000000000dEaD 20 | 21 | COMPOSE_PROJECT_NAME=attestation_front_end 22 | DOCKER_IMAGE_URL=attestation-front-end 23 | LISTEN_PORT=$(FrontEndPort) -------------------------------------------------------------------------------- /scripts/direct-install/helpers/indexer-reset-btc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Reset BTC indexer database. 4 | 5 | systemctl --user stop indexer-btc.service 6 | node dist/src/runIndexer -a BTC -r RESET_ACTIVE 7 | systemctl --user start indexer-btc.service 8 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/indexer-reset-complete.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Reset all indexers databases. 4 | 5 | bash ./scripts/services-stop-all.sh 6 | CONFIG_PATH=.secure node dist/src/runIndexer -a ALGO -r RESET_COMPLETE 7 | bash ./scripts/services-restart-all.sh 8 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/indexer-reset-doge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Reset DOGE indexer database. 4 | 5 | systemctl --user stop indexer-doge.service 6 | CONFIG_PATH=.secure node dist/src/runIndexer -a DOGE -r RESET_ACTIVE 7 | systemctl --user start indexer-doge.service 8 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/indexer-reset-xrp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Reset XRP indexer database. 4 | 5 | systemctl --user stop indexer-xrp.service 6 | CONFIG_PATH=.secure node dist/src/runIndexer -a XRP -r RESET_ACTIVE 7 | systemctl --user start indexer-xrp.service 8 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/run-attester-collector-btc.sh: -------------------------------------------------------------------------------- 1 | # Path to config json. By default it seeks file named config.json in the root folder 2 | CONFIG_PATH=${1:-./configs/config.json} 3 | 4 | # Compile typescript 5 | # yarn tsc 6 | 7 | # Run DataProvider 8 | # node dist/src/spammer/attestation-spammer.js 9 | yarn ts-node src/spammer/attestation-collector.ts \ 10 | -c BTC \ 11 | -r http://127.0.0.1:9650/ext/bc/C/rpc \ 12 | -a artifacts/contracts/StateConnector.sol/StateConnector.json \ 13 | -t $(cat .stateconnector-address) \ 14 | -u http://34.159.118.250:9332/ \ 15 | -s flareadmin \ 16 | -p mcaeEGn6CxYt49XIEYemAB-zSfu38fYEt5dV8zFmGo4= \ 17 | -b 100 \ 18 | -o 1 \ 19 | -f 6 \ 20 | -w 1000 \ 21 | -d 100 \ 22 | -l BTC 23 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/run-attester-collector-xrp.sh: -------------------------------------------------------------------------------- 1 | # Path to config json. By default it seeks file named config.json in the root folder 2 | CONFIG_PATH=${1:-./configs/config.json} 3 | 4 | # Compile typescript 5 | yarn tsc 6 | 7 | # Run DataProvider 8 | # node dist/src/spammer/attestation-spammer.js \ 9 | yarn ts-node src/spammer/attestation-collector.ts \ 10 | -c XRP \ 11 | -r http://127.0.0.1:9650/ext/bc/C/rpc \ 12 | -a artifacts/contracts/StateConnector.sol/StateConnector.json \ 13 | -t $(cat .stateconnector-address) \ 14 | -u https://xrplcluster.com \ 15 | -b 1 \ 16 | -o 1 \ 17 | -f 1 \ 18 | -w 1000 \ 19 | -d 10000 \ 20 | -l XRP 21 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/run-attester-spammer-btc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Start BTC attestations spammer. This is for testing purposes only. 4 | 5 | # Path to config json. By default it seeks file named config.json in the root folder 6 | 7 | CONFIG_PATH=${1:-./configs/config.json} 8 | 9 | # Compile typescript 10 | # yarn tsc 11 | 12 | # Run DataProvider 13 | # node dist/src/spammer/attestation-spammer.js 14 | yarn ts-node src/spammer/attestation-spammer.ts \ 15 | -c BTC \ 16 | -r http://127.0.0.1:9650/ext/bc/C/rpc \ 17 | -a artifacts/contracts/StateConnector.sol/StateConnector.json \ 18 | -t $(cat .stateconnector-address) \ 19 | -u https://bitcoin.flare.network/ \ 20 | -s flareadmin \ 21 | -p mcaeEGn6CxYt49XIEYemAB-zSfu38fYEt5dV8zFmGo4= \ 22 | -b 501 \ 23 | -o 100 \ 24 | -f 6 \ 25 | -w 100 \ 26 | -d 5 \ 27 | -l BTC 28 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/run-attester-spammer-doge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Start DOGE attestations spammer. This is for testing purposes only. 4 | 5 | # Path to config json. By default it seeks file named config.json in the root folder 6 | CONFIG_PATH=${1:-./configs/config.json} 7 | 8 | # Compile typescript 9 | # yarn tsc 10 | 11 | # Run DataProvider 12 | # node dist/src/spammer/attestation-spammer.js \ 13 | yarn ts-node src/spammer/attestation-spammer.ts \ 14 | -c DOGE \ 15 | -r http://127.0.0.1:9650/ext/bc/C/rpc \ 16 | -a artifacts/contracts/StateConnector.sol/StateConnector.json \ 17 | -t $(cat .stateconnector-address) \ 18 | -u https://dogecoin.flare.network/ \ 19 | -s flareadmin \ 20 | -p mcaeEGn6CxYt49XIEYemAB-zSfu38fYEt5dV8zFmGo4= \ 21 | -b 300 \ 22 | -o 10 \ 23 | -f 6 \ 24 | -w 1000 \ 25 | -d 500 \ 26 | -l DOGE 27 | -------------------------------------------------------------------------------- /scripts/direct-install/helpers/run-attester-spammer-xrp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Start XRP attestations spammer. This is for testing purposes only. 4 | 5 | # Path to config json. By default it seeks file named config.json in the root folder 6 | CONFIG_PATH=${1:-./configs/config.json} 7 | 8 | # Compile typescript 9 | yarn tsc 10 | 11 | # Run DataProvider 12 | #yarn ts-node src/spammer/attestation-spammer.ts \ 13 | node dist/src/spammer/attestation-spammer.js -------------------------------------------------------------------------------- /scripts/direct-install/helpers/run-attester-spammer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Start attestations spammer. This is for testing purposes only. 4 | 5 | # Path to config json. By default it seeks file named config.json in the root folder 6 | CONFIG_PATH=${1:-./configs/config.json} 7 | 8 | # Compile typescript 9 | # yarn tsc 10 | 11 | # Run DataProvider 12 | # node dist/src/spammer/attestation-spammer.js 13 | yarn ts-node src/spammer/attestation-spammer.ts -------------------------------------------------------------------------------- /scripts/direct-install/initialize-credentials.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Initialize credentials. Copy all credentials files into folder `credentials`. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | yarn ts-node src/install/installCredentials.ts -------------------------------------------------------------------------------- /scripts/direct-install/install-certbot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install certbot for nginx. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | source ./scripts/direct-install/install-config.sh 7 | 8 | echo -e "${GREENBOLD}Installing CertBot${NC}" 9 | 10 | sudo ln -s /snap/bin/certbot /usr/bin/certbot 11 | sudo apt install certbot -y 12 | sudo certbot certonly --standalone -d $HOSTNAME -m $CERT_EMAIL --agree-tos -------------------------------------------------------------------------------- /scripts/direct-install/install-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./scripts/direct-install/install-config.sh 4 | 5 | failed=false 6 | 7 | check() { 8 | if $2; then 9 | echo -e "${GREENBOLD}Install ${NC}${BOLD}$1${GREENBOLD} chain Attestation Client${NC}" 10 | 11 | if [ "$3" = "" ] ; then 12 | echo -e " ${REDBOLD}ERROR: Secret for $1 not set.${NC}" 13 | echo -e " Add ${BOLD}export $3=${NC} into file ${REDBOLD}.config.secrets.sh${NC}" 14 | failed=true 15 | fi 16 | fi 17 | } 18 | 19 | check2() { 20 | if $2; then 21 | echo -e "${GREENBOLD}Install ${NC}${BOLD}$1${GREENBOLD} module${NC}" 22 | 23 | if [ "$3" = "" ] ; then 24 | echo -e " ${REDBOLD}ERROR: Secret for $1 not set.${NC}" 25 | echo -e " Add ${BOLD}export $3=${NC} into file ${REDBOLD}.config.secrets.sh${NC}" 26 | failed=true 27 | fi 28 | fi 29 | } 30 | 31 | #source ./.config.secret.sh2 32 | 33 | #check FLARE $INSTALL_FLARE $SECRET_FLARE 34 | #check SONGBIRD $INSTALL_SONGBIRD $SECRET_SONGBIRD 35 | #check COSTON $INSTALL_COSTON $SECRET_COSTON 36 | #check COSTON2 $INSTALL_COSTON2 $SECRET_COSTON2 37 | 38 | #check2 "testnet nodes" $INSTALL_NODES_TESTNET $SECRET_NODES_TESTNET 39 | #check2 "mainnet nodes" $INSTALL_NODES_MAINNET $SECRET_NODES_MAINNET 40 | 41 | if $failed ; then 42 | echo -e "${REDBOLD}Exiting${NC}" 43 | exit 44 | fi -------------------------------------------------------------------------------- /scripts/direct-install/install-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export RED='\033[0;31m' 4 | export GREEN='\033[0;32m' 5 | export WHITE="\033[0;37m" 6 | export NC='\033[0m' # No Color 7 | export REDBOLD="${RED}$(tput bold)" 8 | export GREENBOLD="${GREEN}$(tput bold)" 9 | export WHITEBOLD="${WHITE}$(tput bold)" 10 | export NCNORMAL="${NC}$(tput sgr0)" 11 | export BOLD="$(tput bold)" 12 | 13 | source ./config.modules.sh 14 | 15 | export JSON_CONFIG_PATH=../attestation-suite-config/ -------------------------------------------------------------------------------- /scripts/direct-install/install-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install Attestation Suite dependencies. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | 7 | bash ./scripts/direct-install/install-config.sh 8 | 9 | echo -e "${GREENBOLD}Installing Attestation Suite dependencies${NC}" 10 | 11 | echo -e "${REDBOLD}[1] ${GREENBOLD}Installing ${REDBOLD}nvm${NC}" 12 | # node 13 | sudo apt-get update 14 | sudo apt install curl -y 15 | curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash 16 | 17 | source ~/.profile 18 | source ~/.nvm/nvm.sh 19 | nvm install 16.17.1 20 | nvm alias default 16.17.1 21 | nvm use 16.17.1 22 | 23 | # yarn 24 | echo -e "${REDBOLD}[2] ${GREENBOLD}Installing ${REDBOLD}yarn${NC}" 25 | sudo apt install npm -y 26 | sudo npm install --global yarn -y 27 | 28 | source ~/.profile 29 | 30 | # docker 31 | sudo apt install docker.io -y 32 | 33 | sudo apt install docker-compose -y 34 | 35 | -------------------------------------------------------------------------------- /scripts/direct-install/install-nginx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install nginx and configure it for Attestation Suite. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | 7 | source ./scripts/direct-install/install-config.sh 8 | 9 | echo -e "${GREENBOLD}Installing nginX${NC}" 10 | 11 | sudo apt install nginx -y 12 | 13 | yarn ts-node src/install/install-file.ts -i ./scripts/direct-install/files/nginx.default -o nginX.default 14 | sudo cp nginX.default /etc/nginx/sites-available/default 15 | 16 | sudo service nginx restart 17 | -------------------------------------------------------------------------------- /scripts/direct-install/install-nodes-testnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install test-net nodes for ripple, bitcoin and dogecoin. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | 7 | source ./scripts/direct-install/install-config.sh 8 | 9 | echo -e "${GREENBOLD}Installing testnet nodes${NC}" 10 | 11 | export LOCAL_DIR=$(pwd) 12 | 13 | cd /opt 14 | sudo git clone https://github.com/flare-foundation/connected-chains-docker.git 15 | 16 | cd connected-chains-docker/ 17 | git config --global --add safe.directory /opt/connected-chains-docker 18 | #sudo git checkout testnets 19 | 20 | cd $LOCAL_DIR 21 | env CREDENTIALS_KEY_FILE=credentials.prepared/btc-indexer-verifier/credentials.key yarn ts-node src/install/secureCommand.ts -a installNodesTestNet -f "/opt/connected-chains-docker" -c credentials.prepared/btc-indexer-verifier 22 | 23 | cd /opt/connected-chains-docker 24 | sudo docker-compose -f docker-compose-testnet.yml up -d 25 | 26 | sudo ./algorand-catchup.sh 27 | 28 | echo -e "${GREENBOLD}testnet nodes installed${NC}" 29 | 30 | cd $LOCAL_DIR 31 | -------------------------------------------------------------------------------- /scripts/direct-install/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Main direct-install script. 4 | # It installs Attestation Suite services and selected modules. 5 | # Please refer to [docs/install/direct-installation.md] for more details. 6 | 7 | 8 | source ~/.profile 9 | source ~/.nvm/nvm.sh 10 | 11 | # compile 12 | echo -e "${REDBOLD}[3] ${GREENBOLD}Compile...${NC}" 13 | bash ./scripts/compile.sh 14 | 15 | # install services 16 | sudo loginctl enable-linger ubuntu 17 | bash ./scripts/direct-install/install-services.sh 18 | 19 | # install testnet nodes 20 | if $INSTALL_NODES_TESTNET; then 21 | source ./scripts/direct-install/install-nodes-testnet.sh 22 | fi 23 | 24 | # enable local mysql 25 | if $INSTALL_MYSQL; then 26 | source ./scripts/direct-install/install-mysql.sh 27 | fi 28 | 29 | # install frontend 30 | if $INSTALL_FRONTEND; then 31 | source ./scripts/direct-install/install-certbot.sh 32 | source ./scripts/direct-install/install-nginx.sh 33 | fi -------------------------------------------------------------------------------- /scripts/direct-install/prepare-credentials.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Prepare credential packgares from folder `credentials` into `credentials.prepared`. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | 7 | source ./scripts/direct-install/install-config.sh 8 | 9 | yarn ts-node src/install/secureConfigurations.ts -i credentials -o credentials.prepared 10 | 11 | 12 | -------------------------------------------------------------------------------- /scripts/direct-install/services-restart-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Restart all services for specified modules 4 | 5 | source ./scripts/direct-install/install-config.sh 6 | 7 | if $ENABLE_INDEXER; then 8 | systemctl --user restart indexer-xrp 9 | systemctl --user restart indexer-btc 10 | systemctl --user restart indexer-doge 11 | fi 12 | 13 | if $INSTALL_VERIFIER; then 14 | systemctl --user restart verifier-xrp 15 | systemctl --user restart verifier-btc 16 | systemctl --user restart verifier-doge 17 | fi 18 | 19 | if $ENABLE_MONITOR; then 20 | systemctl --user restart attester-alerts 21 | fi 22 | 23 | if $INSTALL_FLARE; then 24 | systemctl --user restart flare-attester-client 25 | systemctl --user restart flare-webserver 26 | fi 27 | 28 | if $INSTALL_SONGBIRD; then 29 | systemctl --user restart songbird-attester-client 30 | systemctl --user restart songbird-webserver 31 | fi 32 | 33 | if $INSTALL_COSTON; then 34 | systemctl --user restart coston-attester-client 35 | systemctl --user restart coston-webserver 36 | fi 37 | 38 | if $INSTALL_COSTON2; then 39 | systemctl --user restart coston2-attester-client 40 | systemctl --user restart coston2-webserver 41 | fi 42 | 43 | # systemctl --user restart coston-spammer-btc.service 44 | # systemctl --user restart coston-spammer-ltc.service 45 | # systemctl --user restart coston-spammer-xrp.service 46 | # systemctl --user restart coston-spammer-algo.service 47 | # systemctl --user restart coston-spammer-doge.service 48 | 49 | -------------------------------------------------------------------------------- /scripts/direct-install/services-stop-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Stop all services for specified modules 4 | 5 | source ./scripts/direct-install/install-config.sh 6 | 7 | if $ENABLE_INDEXER; then 8 | systemctl --user stop indexer-xrp.service 9 | systemctl --user stop indexer-btc.service 10 | systemctl --user stop indexer-doge.service 11 | fi 12 | 13 | if $INSTALL_VERIFIER; then 14 | systemctl --user stop verifier-xrp 15 | systemctl --user stop verifier-btc 16 | systemctl --user stop verifier-doge 17 | fi 18 | 19 | if $ENABLE_MONITOR; then 20 | systemctl --user stop attester-alerts 21 | fi 22 | 23 | if $INSTALL_FLARE; then 24 | systemctl --user stop flare-attester-client.service 25 | systemctl --user stop flare-webserver.service 26 | fi 27 | 28 | if $INSTALL_SONGBIRD; then 29 | systemctl --user stop songbird-attester-client.service 30 | systemctl --user stop songbird-webserver.service 31 | fi 32 | 33 | if $INSTALL_COSTON; then 34 | systemctl --user stop coston-attester-client.service 35 | systemctl --user stop coston-webserver.service 36 | fi 37 | 38 | if $INSTALL_COSTON2; then 39 | systemctl --user stop coston2-attester-client.service 40 | systemctl --user stop coston2-webserver.service 41 | fi 42 | 43 | # systemctl --user stop coston-spammer-btc.service 44 | # systemctl --user stop coston-spammer-ltc.service 45 | # systemctl --user stop coston-spammer-xrp.service 46 | # systemctl --user stop coston-spammer-algo.service 47 | # systemctl --user stop coston-spammer-doge.service 48 | -------------------------------------------------------------------------------- /scripts/direct-install/services/attester-alerts.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/alerts/alerts.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | 12 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston-attester-client.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runAttestationClient.js -i coston 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston 11 | Environment=FLARE_NETWORK=coston 12 | 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client/ 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston-backend.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/webserver/server.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston 11 | Environment=FLARE_NETWORK=coston 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston-spammer-btc.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/spammer/attestation-spammer.js -c BTC 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston 11 | Environment=FLARE_NETWORK=coston 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client/ 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston-spammer-doge.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/spammer/attestation-spammer.js -c DOGE 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston 11 | Environment=FLARE_NETWORK=coston 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston-spammer-xrp.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/spammer/attestation-spammer.js -c XRP 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston 11 | Environment=FLARE_NETWORK=coston 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston2-attester-client.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runAttestationClient.js -i coston2 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston2 11 | Environment=FLARE_NETWORK=coston2 12 | Environment=SECURE_CONFIG_PATH=credentials.prepared/attester-client 13 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/attester-client/credentials.key 14 | 15 | 16 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 17 | 18 | [Install] 19 | WantedBy=multi-user.target 20 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston2-backend.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/webserver/server.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston2 11 | Environment=FLARE_NETWORK=coston2 12 | Environment=SECURE_CONFIG_PATH=credentials.prepared/webserver 13 | 14 | 15 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /scripts/direct-install/services/coston2-web-server.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runWebServer.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/coston2 11 | Environment=FLARE_NETWORK=coston2 12 | Environment=SECURE_CONFIG_PATH=credentials.prepared/webserver 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /scripts/direct-install/services/flare-attester-client.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runAttestationClient.js -i flare 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/flare 11 | Environment=FLARE_NETWORK=Flare 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/flare-backend.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/webserver/server.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/flare 11 | Environment=FLARE_NETWORK=Flare 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/indexer-btc.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runIndexer.js -a BTC 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | Environment=SECURE_CONFIG_PATH=credentials.prepared/btc-indexer-verifier 12 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/btc-indexer-verifier/credentials.key 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/services/indexer-doge.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runIndexer.js -a DOGE 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | Environment=SECURE_CONFIG_PATH=credentials.prepared/doge-indexer-verifier 12 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/doge-indexer-verifier/credentials.key 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/services/indexer-xrp.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runIndexer.js -a XRP 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | Environment=SECURE_CONFIG_PATH=credentials.prepared/xrp-indexer-verifier 12 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/xrp-indexer-verifier/credentials.key 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/services/songbird-attester-client.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runAttestationClient.js -i songbird 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/songbird 11 | Environment=FLARE_NETWORK=Songbird 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/songbird-backend.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/webserver/server.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/songbird 11 | Environment=FLARE_NETWORK=Songbird 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/songbird-spammer.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/spammer/attestation-spammer.js 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/songbird 11 | Environment=FLARE_NETWORK=Songbird 12 | 13 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /scripts/direct-install/services/verifier-btc.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runVerifierServer.js -a btc 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | Environment=SECURE_CONFIG_PATH=credentials.prepared/btc-indexer-verifier 12 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/btc-indexer-verifier/credentials.key 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/services/verifier-doge.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runVerifierServer.js -a doge 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | Environment=SECURE_CONFIG_PATH=credentials.prepared/doge-indexer-verifier 12 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/doge-indexer-verifier/credentials.key 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/services/verifier-xrp.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=/home/ubuntu/.nvm/versions/node/v16.17.1/bin/node /home/ubuntu/attestation-suite/attestation-client/dist/src/runVerifierServer.js -a xrp 3 | Restart=always 4 | # User=ubuntu 5 | # Use 'nogroup' group for Ubuntu/Debian 6 | # use 'nobody' group for Fedora 7 | # Group=nogroup 8 | Environment=PATH=/usr/bin:/usr/local/bin 9 | Environment=NODE_ENV=production 10 | Environment=LOG_PATH=./logs/global 11 | Environment=SECURE_CONFIG_PATH=credentials.prepared/xrp-indexer-verifier 12 | Environment=CREDENTIALS_KEY_FILE=credentials.prepared/xrp-indexer-verifier/credentials.key 13 | 14 | WorkingDirectory=/home/ubuntu/attestation-suite/attestation-client 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /scripts/direct-install/update-credentials.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Update credential and restart services. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | yarn ts-node src/direct-install/install/secureConfigurations.ts -i credentials -o credentials.prepared 7 | 8 | # restart all services 9 | source ./scripts/direct-install/services-restart-all.sh 10 | 11 | -------------------------------------------------------------------------------- /scripts/direct-install/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Pull new code from git, compile and restart services. 4 | # Please refer to [docs/install/direct-installation.md] for more details. 5 | 6 | #rm -f yarn.lock 7 | git pull 8 | bash ./scripts/compile.sh 9 | bash ./scripts/direct-install/services-restart-all.sh -------------------------------------------------------------------------------- /src/admin/menuItem.ts: -------------------------------------------------------------------------------- 1 | import { MenuItemBase } from "./menuItemBase"; 2 | import { MenuItemCommand } from "./menuItemCommand"; 3 | import { MenuItemLog } from "./menuItemLog"; 4 | import { MenuItemService } from "./menuItemService"; 5 | export class MenuItem { 6 | item: MenuItemBase; 7 | 8 | constructor(item: MenuItemBase) { 9 | this.item = item; 10 | } 11 | 12 | parent() { 13 | return new MenuItem(this.item.itemParent); 14 | } 15 | 16 | addSubmenu(name: string): MenuItem { 17 | return new MenuItem(this.item.add(new MenuItemBase(name, this.item))); 18 | } 19 | 20 | addCommand(name: string, command: string): MenuItem { 21 | return new MenuItem(this.item.add(new MenuItemCommand(name, command, this.item))); 22 | } 23 | addService(name: string, serviceName: string): MenuItem { 24 | return new MenuItem(this.item.add(new MenuItemService(name, serviceName, this.item))); 25 | } 26 | addLog(name: string, filename: string): MenuItem { 27 | return new MenuItem(this.item.add(new MenuItemLog(name, filename, this.item))); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/admin/menuItemBase.ts: -------------------------------------------------------------------------------- 1 | import { logException } from "../utils/logging/logger"; 2 | import { Menu } from "./menu"; 3 | 4 | export class MenuItemBase { 5 | name = ""; 6 | displayName: string = null; 7 | 8 | menu: Menu; 9 | 10 | items = []; 11 | itemParent: MenuItemBase; 12 | 13 | constructor(name: string, parent: MenuItemBase) { 14 | this.name = name; 15 | this.menu = parent?.menu; 16 | this.itemParent = parent; 17 | } 18 | 19 | refresh(newLocation = false) { 20 | if (this.menu.activeItem === this.itemParent) { 21 | this.menu.refresh(newLocation); 22 | } 23 | } 24 | 25 | getDisplay() { 26 | return this.displayName ? this.displayName : this.name; 27 | } 28 | 29 | add(item: MenuItemBase): MenuItemBase { 30 | this.items.push(item); 31 | 32 | return item; 33 | } 34 | 35 | async onExecute?(); 36 | execute() { 37 | if (this.items != null && this.items.length > 0) { 38 | this.menu.navigate(this); 39 | return; 40 | } 41 | 42 | try { 43 | this.onExecute(); 44 | } catch (error) { 45 | logException(error, "MenuBase::execute"); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/admin/menuItemCommand.ts: -------------------------------------------------------------------------------- 1 | import { getGlobalLogger } from "../utils/logging/logger"; 2 | import { sleepMs } from "../utils/helpers/utils"; 3 | import { MenuItemBase } from "./menuItemBase"; 4 | import { exec } from "child_process"; 5 | 6 | export class MenuItemCommand extends MenuItemBase { 7 | command: string; 8 | 9 | static working = false; 10 | 11 | constructor(name: string, command: string, parent: MenuItemBase) { 12 | super(name, parent); 13 | this.command = command; 14 | } 15 | 16 | async onExecute() { 17 | getGlobalLogger().info(`execute ^g${this.command}^^`); 18 | 19 | MenuItemCommand.working = true; 20 | 21 | let done = false; 22 | 23 | const execObj = exec(this.command); 24 | 25 | execObj.stdout.on("data", function (data) { 26 | console.log(data.replace(/\n$/, "")); 27 | }); 28 | 29 | execObj.on("exit", function () { 30 | done = true; 31 | }); 32 | 33 | // wait until exec is completed 34 | while (!done) { 35 | await sleepMs(100); 36 | } 37 | 38 | MenuItemCommand.working = false; 39 | 40 | getGlobalLogger().info("exec completed\n"); 41 | 42 | this.refresh(true); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/attester/BitVoteData.ts: -------------------------------------------------------------------------------- 1 | import { prefix0x, unPrefix0x } from "@flarenetwork/mcc"; 2 | import { BitVote } from "../../typechain-web3-v1/BitVoting"; 3 | 4 | /** 5 | * Choose Round data event emitted by attestation providers when they choose which requests can be attested to 6 | */ 7 | export class BitVoteData { 8 | sender: string; 9 | timestamp: number; 10 | data: string; 11 | 12 | constructor(event?: BitVote) { 13 | if (!event) return; 14 | this.sender = event.returnValues.sender; 15 | this.timestamp = parseInt(event.returnValues.timestamp, 10); 16 | this.data = event.returnValues.data; 17 | if (!this.data || unPrefix0x(this.data).length < 2) { 18 | throw new Error("Incorrect bit vote"); 19 | } 20 | } 21 | 22 | /** 23 | * Checks if round check byte of data matches the round. 24 | * @param roundId 25 | * @returns 26 | */ 27 | roundCheck(roundId: number): boolean { 28 | if (!this.data || unPrefix0x(this.data).length < 2) { 29 | return false; 30 | } 31 | return parseInt(unPrefix0x(this.data).slice(0, 2), 16) === roundId % 256; 32 | } 33 | 34 | /** 35 | * Returns bit vote part of the data (without round check byte) 36 | */ 37 | get bitVote(): string { 38 | if (!this.data || unPrefix0x(this.data).length < 2) { 39 | return "0x00"; 40 | } 41 | return prefix0x(unPrefix0x(this.data).slice(2)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/attester/configs/AttesterWebOptions.ts: -------------------------------------------------------------------------------- 1 | import { optional } from "@flarenetwork/mcc"; 2 | 3 | /** 4 | * Flare chain connection configuration class for an attestation client. 5 | */ 6 | 7 | export class AttesterWebOptions { 8 | /** 9 | * Private key for submissions to StateConnector and BitVoting contracts onto Flare chain 10 | */ 11 | public accountPrivateKey = ""; 12 | 13 | /** 14 | * RPC connection for Flare chain, that is used in web3.js library. Can be REST or websocket. 15 | */ 16 | public rpcUrl = ""; 17 | 18 | /** 19 | * StateConnector contract address on the Flare chain. 20 | */ 21 | public stateConnectorContractAddress = ""; 22 | 23 | /** 24 | * BitVoting contract address on the Flare chain. 25 | */ 26 | @optional() public bitVotingContractAddress = ""; 27 | 28 | /** 29 | * Gas limit for sending transactions. Defined as string. 30 | */ 31 | @optional() public gasLimit = "2500000"; 32 | 33 | /** 34 | * Gas price is calculated from the network. The addition (in wei) is added to make the call more competitive. 35 | * Default is set to 20 Gwei. 36 | */ 37 | @optional() public gasPriceAddition = "20000000000"; 38 | 39 | /** 40 | * Polling time for collection data from the Flare chain (new blocks, new events). 41 | */ 42 | @optional() public refreshEventsMs = 100; 43 | } 44 | -------------------------------------------------------------------------------- /src/attester/configs/GlobalAttestationConfig.ts: -------------------------------------------------------------------------------- 1 | import { AdditionalTypeInfo, IReflection } from "../../utils/reflection/reflection"; 2 | 3 | /** 4 | * Class providing global attestation configuration for each source and attestation type 5 | * from the @param startRoundId on. 6 | * This is the deserialization class for relevant JSON configuration. 7 | */ 8 | export class GlobalAttestationConfig implements IReflection { 9 | /** 10 | * Round id from which the global configuration is valid 11 | */ 12 | startRoundId: number; 13 | /** 14 | * Set of assigner addresses that define the default set addresses. 15 | * `StateConnector` smart contract contains a mapping between addresses which can be updated 16 | * by calling function `updateAttestorAddressMapping(address)`. 17 | * A validator node for each Flare network has a set of 9-predefined assigners. Each 18 | * such assigner can using the above method define one member of the attestation set. 19 | */ 20 | defaultSetAssignerAddresses: string[] = []; 21 | 22 | getAdditionalTypeInfo(obj: any): AdditionalTypeInfo { 23 | const info = new AdditionalTypeInfo(); 24 | info.arrayMap.set("defaultSetAssignerAddresses", "string"); 25 | return info; 26 | } 27 | 28 | instantiate(): GlobalAttestationConfig { 29 | return new GlobalAttestationConfig(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/attester/experimental/IntegerTimeScheduler.ts: -------------------------------------------------------------------------------- 1 | type ScheduledCallBack = () => Promise | void; 2 | 3 | export class IntegerTimeScheduler { 4 | // integer time 5 | time: number; 6 | timeQueue: Map; 7 | 8 | scheduleAfter(callback: ScheduledCallBack, after: number) { 9 | if (after <= 0) { 10 | throw new Error("Parameter 'after' must be greater than 0"); 11 | } 12 | let position = this.time + Math.floor(after); 13 | let entries = this.timeQueue.get(position); 14 | if (!entries) { 15 | entries = []; 16 | this.timeQueue.set(position, entries); 17 | } 18 | entries.push(callback); 19 | } 20 | 21 | get isExecuted(): boolean { 22 | let entries = this.timeQueue.get(this.time); 23 | return !entries || entries.length === 0; 24 | } 25 | 26 | // Optimize for all increments 27 | async next() { 28 | let entries = this.timeQueue.get(this.time); 29 | if (!this.isExecuted) { 30 | let promises = entries.map((entry) => entry()); 31 | await Promise.all(promises); 32 | } 33 | this.timeQueue.set(this.time, undefined); 34 | this.time++; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/attester/types/AttestationRoundEnums.ts: -------------------------------------------------------------------------------- 1 | export enum AttestationRoundPhase { 2 | collect, 3 | choose, 4 | commit, 5 | reveal, 6 | finalise, 7 | } 8 | 9 | // !!! STATUS ORDER IS IMPORTANT. It is crucial that the round can progress only to later status 10 | // and not back 11 | export enum AttestationRoundStatus { 12 | collecting, 13 | bitVotingClosed, // choose phase is finished and at least one block with bigger timestamp is mined or enough time has passed 14 | chosen, // bit voting result calculated 15 | commitDataPrepared, // commit data (Merkle tree) calculated based on bit voting result 16 | 17 | committed, // receipt for submitAttestation which committed the commit data has been received 18 | revealed, // receipt for submitAttestation which revealed the data has been received 19 | 20 | error, 21 | processingTimeout, 22 | } 23 | export const NO_VOTE = "0x00"; 24 | -------------------------------------------------------------------------------- /src/entity/attester/dbAttestationRequest.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index } from "typeorm"; 2 | import { BaseEntity } from "../base/BaseEntity"; 3 | 4 | /** 5 | * Format for storing the data from a resolved attestation round 6 | */ 7 | @Entity({ name: "attestation_request" }) 8 | export class DBAttestationRequest extends BaseEntity { 9 | @Column() @Index() roundId: number = 0; 10 | @Column() @Index() blockNumber: string = ""; 11 | @Column() @Index() logIndex: number = 0; 12 | 13 | @Column({ type: "text" }) requestBytes: string = ""; 14 | @Column({ type: "text" }) request: string = ""; 15 | @Column() verificationStatus: string = ""; 16 | // nullable due to migration 17 | @Column({ nullable: true }) attestationStatus: string; 18 | @Column({ type: "text" }) response: string = ""; 19 | @Column() exceptionError: string = ""; 20 | @Column() hashData: string = ""; 21 | } 22 | -------------------------------------------------------------------------------- /src/entity/attester/dbRoundResult.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryColumn } from "typeorm"; 2 | 3 | /** 4 | * Format for storing the data from a resolved attestation round 5 | */ 6 | @Entity({ name: "round_result" }) 7 | export class DBRoundResult { 8 | // extends BaseEntity { 9 | @PrimaryColumn() roundId: number = 0; 10 | @Column({ nullable: true }) @Index() merkleRoot: string; 11 | @Column({ nullable: true }) @Index() maskedMerkleRoot: string; 12 | @Column({ nullable: true }) @Index() random: string; 13 | @Column({ nullable: true }) finalizedTimestamp: number; 14 | 15 | @Column({ nullable: true }) commitTransactionId: string; 16 | @Column({ nullable: true }) commitNonce: number; 17 | @Column({ nullable: true }) commitTimestamp: number; 18 | 19 | @Column({ nullable: true }) revealTransactionId: string; 20 | @Column({ nullable: true }) revealNonce: number; 21 | @Column({ nullable: true }) revealTimestamp: number; 22 | @Column({ nullable: true }) transactionCount: number; 23 | @Column({ nullable: true }) validTransactionCount: number; 24 | 25 | @Column({ nullable: true, type: "text" }) bitVote: string; 26 | @Column({ nullable: true }) bitVoteTransactionId: string; 27 | @Column({ nullable: true }) bitVoteNonce: number; 28 | @Column({ nullable: true }) bitVoteTimestamp: number; 29 | 30 | @Column({ nullable: true, type: "text" }) bitVoteResult: string; 31 | @Column({ nullable: true }) bitVoteResultTimestamp: number; 32 | 33 | // This field is either empty or contains protest string 34 | @Column({ nullable: true }) rejectIndex: number; 35 | } 36 | -------------------------------------------------------------------------------- /src/entity/attester/dbVotingRoundResult.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index } from "typeorm"; 2 | import { BaseEntity } from "../base/BaseEntity"; 3 | 4 | /** 5 | * Format for storing verification data of an attestation 6 | */ 7 | @Entity({ name: "voting_round_result" }) 8 | export class DBVotingRoundResult extends BaseEntity { 9 | @Column() @Index() roundId: number = 0; 10 | @Column() @Index() hash: string = ""; 11 | // temporary nullable (migration) 12 | @Column({ type: "text", nullable: true }) requestBytes: string = ""; 13 | @Column({ type: "text" }) request: string = ""; 14 | @Column({ type: "text" }) response: string = ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/entity/base/BaseEntity.ts: -------------------------------------------------------------------------------- 1 | import { PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | export abstract class BaseEntity { 4 | /** 5 | * Auto incremented id 6 | */ 7 | @PrimaryGeneratedColumn({ type: "int" }) 8 | id: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/entity/indexer/dbBlock.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryColumn } from "typeorm"; 2 | 3 | /** 4 | * Format for storing block data in indexer database 5 | */ 6 | export class DBBlockBase { 7 | @PrimaryColumn({ type: "varchar" }) 8 | blockHash!: string; 9 | 10 | @Column() 11 | @Index() 12 | blockNumber!: number; 13 | 14 | @Column() 15 | @Index() 16 | timestamp!: number; 17 | 18 | @Column({ nullable: true }) 19 | transactions: number; 20 | 21 | @Column({ nullable: true }) 22 | @Index() 23 | confirmed: boolean; 24 | 25 | // relevant only if confirmed not true 26 | @Column({ nullable: true }) 27 | @Index() 28 | numberOfConfirmations: number; 29 | 30 | @Column({ nullable: true }) 31 | @Index() 32 | previousBlockHash: string; 33 | } 34 | 35 | export type IDBBlockBase = new () => DBBlockBase; 36 | 37 | @Entity({ name: "btc_block" }) 38 | export class DBBlockBTC extends DBBlockBase {} 39 | @Entity({ name: "doge_block" }) 40 | export class DBBlockDOGE extends DBBlockBase {} 41 | @Entity({ name: "xrp_block" }) 42 | export class DBBlockXRP extends DBBlockBase {} 43 | -------------------------------------------------------------------------------- /src/entity/indexer/dbState.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, PrimaryColumn } from "typeorm"; 2 | 3 | @Entity({ name: "state" }) 4 | export class DBState { 5 | @PrimaryColumn({ type: "varchar" }) 6 | name!: string; 7 | 8 | @Column() 9 | valueString: string = ""; 10 | 11 | @Column({ type: "bigint" }) 12 | valueNumber: number = 0; 13 | 14 | @Column() 15 | timestamp: number = 0; 16 | 17 | @Column({ nullable: true }) 18 | comment: string = ""; 19 | } 20 | -------------------------------------------------------------------------------- /src/external-libs/AttestationResponse.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Attestation status 3 | */ 4 | export enum AttestationResponseStatus { 5 | /** 6 | * Attestation request is valid. 7 | */ 8 | VALID = "VALID", 9 | /** 10 | * Attestation request is invalid. 11 | */ 12 | INVALID = "INVALID", 13 | /** 14 | * Attestation request cannot be confirmed neither rejected by the verifier at the moment. 15 | */ 16 | INDETERMINATE = "INDETERMINATE", 17 | } 18 | /** 19 | * Object returned as a result of attestation. 20 | * If status is 'VALID' then parameters @param response contains attestation response. 21 | * Otherwise, @param response is undefined. 22 | */ 23 | 24 | export class AttestationResponse { 25 | /** 26 | * Verification status. 27 | */ 28 | status!: AttestationResponseStatus; 29 | /** 30 | * Attestation response. 31 | */ 32 | response?: RES; 33 | } 34 | -------------------------------------------------------------------------------- /src/external-libs/interfaces.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generic interface for the request of an attestation request. 3 | */ 4 | export interface ARBase { 5 | attestationType: string; 6 | sourceId: string; 7 | messageIntegrityCode?: string; 8 | requestBody: any; 9 | } 10 | 11 | /** 12 | * Generic interface for the response of an attestation request. 13 | */ 14 | export interface ARESBase { 15 | attestationType: string; 16 | sourceId: string; 17 | votingRound: string; 18 | lowestUsedTimestamp: string; 19 | requestBody: any; 20 | responseBody: any; 21 | } 22 | 23 | /** 24 | * Generic interface for example data usually randomly generated for testing purposes and examples. 25 | */ 26 | export interface ExampleData { 27 | requestNoMic: RNM; 28 | request: REQ; 29 | response: RES; 30 | messageIntegrityCode: string; 31 | encodedRequestZeroMic: string; 32 | encodedRequest: string; 33 | } 34 | -------------------------------------------------------------------------------- /src/indexed-query-manager/random-attestation-requests/README.md: -------------------------------------------------------------------------------- 1 | # Random attestation requests 2 | 3 | This folder contains a helper code for creating random attestation requests by querying indexer's database for specific transactions and then producing the randomized test transactions. 4 | 5 | The helper code is used for testing and for spammer (a client producing random request and sending them to the network). It is not necessary to audit the code. 6 | -------------------------------------------------------------------------------- /src/indexer/IndexerConfig.ts: -------------------------------------------------------------------------------- 1 | import { optional } from "@flarenetwork/mcc"; 2 | import { ChainConfig } from "../attester/configs/ChainConfig"; 3 | import { DatabaseConnectOptions } from "../utils/database/DatabaseConnectOptions"; 4 | import { AdditionalTypeInfo, IReflection } from "../utils/reflection/reflection"; 5 | 6 | /** 7 | * Indexer configuration. Top level JSON deserialization object. 8 | */ 9 | export class IndexerConfig implements IReflection { 10 | /** 11 | * Enable chain back syncing 12 | */ 13 | @optional() public syncEnabled = true; 14 | /** 15 | * How many days back to sync (decimals are supported) 16 | */ 17 | @optional() public syncTimeDays = 2.5; 18 | /** 19 | * How much time in ms to wait before checking for new block 20 | */ 21 | @optional() public blockCollectTimeMs = 1000; 22 | 23 | /** 24 | * How much time to wait before checking for a new block while syncing 25 | */ 26 | @optional() public syncUpdateTimeMs = 10000; 27 | 28 | /** 29 | * Indexer database configuration connection options 30 | */ 31 | indexerDatabase = new DatabaseConnectOptions(); 32 | 33 | /** 34 | * Blockchain configurations options 35 | */ 36 | chainConfiguration = new ChainConfig(); 37 | 38 | instantiate() { 39 | return new IndexerConfig(); 40 | } 41 | 42 | getAdditionalTypeInfo(obj: any): AdditionalTypeInfo { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/indexer/chain-collector-helpers/augmentBlock.ts: -------------------------------------------------------------------------------- 1 | import { BlockBase } from "@flarenetwork/mcc"; 2 | import { DBBlockBase, IDBBlockBase } from "../../entity/indexer/dbBlock"; 3 | import { prepareString } from "../../utils/helpers/utils"; 4 | 5 | /** 6 | * Creates database entity for a confirmed block 7 | * @param dbBlockClass 8 | * @param block 9 | * @returns 10 | */ 11 | export function augmentBlock(dbBlockClass: IDBBlockBase, block: BlockBase): DBBlockBase { 12 | const entity = new dbBlockClass(); 13 | entity.blockNumber = block.number; 14 | entity.blockHash = prepareString(block.stdBlockHash, 128); 15 | entity.timestamp = block.unixTimestamp; 16 | entity.confirmed = true; 17 | entity.transactions = block.transactionCount; 18 | entity.previousBlockHash = prepareString(block.previousBlockHash, 128); 19 | 20 | return entity; 21 | } 22 | -------------------------------------------------------------------------------- /src/indexer/chain-collector-helpers/types.ts: -------------------------------------------------------------------------------- 1 | import { DBBlockBase } from "../../entity/indexer/dbBlock"; 2 | import { DBTransactionBase } from "../../entity/indexer/dbTransaction"; 3 | 4 | export interface onSaveSig { 5 | (block: DBBlockBase, transactions: DBTransactionBase[]): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/indexer/preparedBlock.ts: -------------------------------------------------------------------------------- 1 | import { DBBlockBase } from "../entity/indexer/dbBlock"; 2 | import { DBTransactionBase } from "../entity/indexer/dbTransaction"; 3 | 4 | /** 5 | * Record for prepared blocks. 6 | */ 7 | export class PreparedBlock { 8 | block: DBBlockBase; 9 | transactions: DBTransactionBase[]; 10 | 11 | constructor(block: DBBlockBase, transactions: DBTransactionBase[]) { 12 | this.block = block; 13 | this.transactions = transactions; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/install/getSecureValue.ts: -------------------------------------------------------------------------------- 1 | import * as yargs from "yargs"; 2 | import { getSecureValue, initializeJSONsecure } from "../utils/config/jsonSecure"; 3 | 4 | const DEFAULT_SECURE_CONFIG_PATH = "../attestation-suite-config"; 5 | 6 | const args = yargs 7 | .option("defaultSecureConfigPath", { alias: "p", type: "string", description: "start folder", default: DEFAULT_SECURE_CONFIG_PATH, demand: false }) 8 | .option("network", { alias: "n", type: "string", description: "network", default: "Coston", demand: false }) 9 | .option("secureVariable", { alias: "e", type: "string", description: "secure variable name", default: "", demand: false }).argv; 10 | 11 | async function run() { 12 | await initializeJSONsecure(args["defaultSecureConfigPath"], args["network"]); 13 | 14 | const secureValue = getSecureValue(args["secureVariable"]); 15 | console.log(secureValue); 16 | } 17 | 18 | run() 19 | .then(() => process.exit(0)) 20 | .catch((error) => { 21 | console.error(error); 22 | process.exit(1); 23 | }); 24 | -------------------------------------------------------------------------------- /src/install/utils.ts: -------------------------------------------------------------------------------- 1 | import stringify from "safe-stable-stringify"; 2 | 3 | export function muteMySQLPasswords(command: string | any) { 4 | let str = stringify(command); 5 | return str.replace(/\-p[^ ]+/g, "-p***********"); 6 | } 7 | 8 | export function replaceAllVars(source: string, varName: string, to: string): string { 9 | while (true) { 10 | const newSource = source.replace(`$(${varName})`, to); 11 | if (newSource === source) return source; 12 | source = newSource; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/monitor/MonitorConfigBase.ts: -------------------------------------------------------------------------------- 1 | import { optional } from "@flarenetwork/mcc"; 2 | import { AttLogger } from "../utils/logging/logger"; 3 | import { MonitorBase } from "./MonitorBase"; 4 | import { MonitorConfig } from "./MonitorConfiguration"; 5 | 6 | /** 7 | * Monitor configuration base class. 8 | */ 9 | export class MonitorConfigBase { 10 | name = ""; 11 | 12 | @optional() disabled: false; 13 | @optional() restart = ""; 14 | @optional() timeRestart = 15; 15 | 16 | /** 17 | * Return monitor name. 18 | */ 19 | getName?(): string; 20 | 21 | /** 22 | * Create monitor for this configuration. 23 | * @param config 24 | * @param baseConfig 25 | * @param logger 26 | */ 27 | createMonitor?(config: MonitorConfigBase, baseConfig: MonitorConfig, logger: AttLogger): MonitorBase; 28 | } 29 | -------------------------------------------------------------------------------- /src/runDockerStats.ts: -------------------------------------------------------------------------------- 1 | import { TraceManager, traceManager } from "@flarenetwork/mcc"; 2 | import { exit } from "process"; 3 | import { DockerStats } from "./monitor/DockerStats"; 4 | import { getGlobalLogger, setLoggerName } from "./utils/logging/logger"; 5 | 6 | traceManager.displayStateOnException = false; 7 | traceManager.displayRuntimeTrace = false; 8 | TraceManager.enabled = false; 9 | 10 | const dockerStats = new DockerStats(); 11 | 12 | setLoggerName("docker-stats"); 13 | 14 | // allow only one instance of the application 15 | var instanceName = `docker-stats`; 16 | 17 | var SingleInstance = require("single-instance"); 18 | var locker = new SingleInstance(instanceName); 19 | 20 | locker 21 | .lock() 22 | .then(function () { 23 | // eslint-disable-next-line 24 | dockerStats.runDockerStats(); 25 | }) 26 | .catch(function (err) { 27 | getGlobalLogger().error(`unable to start application. ^w${instanceName}^^ is locked`); 28 | 29 | // Quit the application 30 | exit(5); 31 | }); 32 | -------------------------------------------------------------------------------- /src/runMonitor.ts: -------------------------------------------------------------------------------- 1 | import { TraceManager, traceManager } from "@flarenetwork/mcc"; 2 | import { setLoggerName } from "./utils/logging/logger"; 3 | import { MonitorManager } from "./monitor/MonitorManager"; 4 | 5 | traceManager.displayStateOnException = false; 6 | traceManager.displayRuntimeTrace = false; 7 | TraceManager.enabled = false; 8 | 9 | const monitorManager = new MonitorManager(); 10 | 11 | setLoggerName("monitor"); 12 | 13 | // eslint-disable-next-line 14 | monitorManager.runMonitor(); 15 | -------------------------------------------------------------------------------- /src/runVerifierServer.ts: -------------------------------------------------------------------------------- 1 | import { TraceManager, traceManager } from "@flarenetwork/mcc"; 2 | import * as yargs from "yargs"; 3 | import { runVerifierServer } from "./servers/verifier-server/src/verifierServer"; 4 | import { getGlobalLogger, setLoggerName } from "./utils/logging/logger"; 5 | 6 | const args = yargs.option("chain", { alias: "a", type: "string", description: "Chain", default: "", demand: false }).argv; 7 | 8 | traceManager.displayStateOnException = false; 9 | traceManager.displayRuntimeTrace = false; 10 | TraceManager.enabled = false; 11 | 12 | setLoggerName("verifierServer"); 13 | 14 | if (args["chain"]) { 15 | process.env.VERIFIER_TYPE = args["chain"]; 16 | getGlobalLogger().debug(`chain ${process.env.VERIFIER_TYPE} (set with command line)`); 17 | } else { 18 | getGlobalLogger().debug(`chain ${process.env.VERIFIER_TYPE} (set with env)`); 19 | } 20 | 21 | // eslint-disable-next-line 22 | runVerifierServer(); 23 | -------------------------------------------------------------------------------- /src/runWebServer.ts: -------------------------------------------------------------------------------- 1 | import { TraceManager, traceManager } from "@flarenetwork/mcc"; 2 | import { runWebserver } from "./servers/web-server/src/webserver"; 3 | import { setLoggerName } from "./utils/logging/logger"; 4 | 5 | traceManager.displayStateOnException = false; 6 | traceManager.displayRuntimeTrace = false; 7 | TraceManager.enabled = false; 8 | 9 | setLoggerName("webserver"); 10 | 11 | // eslint-disable-next-line 12 | runWebserver(); 13 | -------------------------------------------------------------------------------- /src/scripts/create-routes-folder.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | function createRoutesFolder() { 4 | const dir = "routes"; 5 | 6 | if (!fs.existsSync(dir)) { 7 | fs.mkdirSync(dir); 8 | } 9 | } 10 | 11 | createRoutesFolder(); 12 | -------------------------------------------------------------------------------- /src/scripts/deploy-bit-voting.ts: -------------------------------------------------------------------------------- 1 | const BitVoting = artifacts.require("BitVoting"); 2 | 3 | async function deploy() { 4 | const bitVoting = await BitVoting.new(); 5 | console.log(`Contract deployed at: ${bitVoting.address}`); 6 | } 7 | 8 | deploy() 9 | .then(() => { 10 | process.exit(0); 11 | }) 12 | .catch((e) => { 13 | console.log(e); 14 | process.exit(1); 15 | }); 16 | -------------------------------------------------------------------------------- /src/servers/common/src/api-models/ApiBase.ts: -------------------------------------------------------------------------------- 1 | export interface ApiBase { 2 | id: number; 3 | } 4 | -------------------------------------------------------------------------------- /src/servers/common/src/api-models/PaginatedList.ts: -------------------------------------------------------------------------------- 1 | export class PaginatedList { 2 | /** 3 | * Count of all items satisfying 'paginatable' request. 4 | */ 5 | count?: number; 6 | /** 7 | * Response items. 8 | */ 9 | items?: T[]; 10 | /** 11 | * Limit got from request 12 | */ 13 | limit?: number; 14 | /** 15 | * Offset got from request 16 | */ 17 | offset?: number; 18 | 19 | constructor(items: T[], count?: number, limit?: number, offset?: number) { 20 | this.items = items; 21 | this.count = count; 22 | this.limit = limit; 23 | this.offset = offset; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/servers/common/src/api-models/PaginationRequest.ts: -------------------------------------------------------------------------------- 1 | export interface PaginationRequest { 2 | limit?: number; 3 | offset?: number; 4 | sort?: "ASC" | "DESC"; 5 | sortBy?: string; 6 | query?: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/servers/common/src/api-models/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ApiBase"; 2 | export * from "./ApiResponse"; 3 | export * from "./PaginatedList"; 4 | export * from "./PaginationRequest"; 5 | -------------------------------------------------------------------------------- /src/servers/common/src/common.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | 3 | @Module({ 4 | providers: [], 5 | exports: [], 6 | }) 7 | export class CommonModule {} 8 | -------------------------------------------------------------------------------- /src/servers/common/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./common.module"; 2 | export * from "./api-models"; 3 | -------------------------------------------------------------------------------- /src/servers/common/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "../../../dist/src/servers/common" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/config-models/MonitorserverConfig.ts: -------------------------------------------------------------------------------- 1 | import { AdditionalTypeInfo, IReflection } from "../../../../utils/reflection/reflection"; 2 | 3 | export class MonitorserverConfig implements IReflection { 4 | port: number = 9600; 5 | 6 | instantiate(): MonitorserverConfig { 7 | return new MonitorserverConfig(); 8 | } 9 | 10 | getAdditionalTypeInfo(obj: any): AdditionalTypeInfo { 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/controllers/prometheus.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Header } from "@nestjs/common"; 2 | import { ApiTags } from "@nestjs/swagger"; 3 | import { PrometheusEngineService } from "../services/prometheus-engine.service"; 4 | 5 | @ApiTags("Status") 6 | @Controller("/") 7 | export class PrometheusController { 8 | constructor(private proofEngine: PrometheusEngineService) {} 9 | 10 | @Get("metrics") 11 | @Header("Content-Type", "text/html") 12 | public async servicePrometheusMetrics(): Promise { 13 | return await this.proofEngine.servicePrometheusMetrics(); 14 | } 15 | 16 | @Get("status/json") 17 | public async serviceStatusjson(): Promise { 18 | return await this.proofEngine.serviceStatusJson(); 19 | } 20 | 21 | @Get("status") 22 | @Header("Content-Type", "text/html") 23 | public async serviceStatusHtml(): Promise { 24 | return await this.proofEngine.serviceStatusHtml(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/dtos/ServiceStatus.dto.ts: -------------------------------------------------------------------------------- 1 | import { MonitorStatus, PerformanceMetrics } from "../../../../monitor/MonitorBase"; 2 | 3 | export interface ServiceStatus { 4 | monitor: MonitorStatus[]; 5 | perf: PerformanceMetrics[]; 6 | } 7 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/dtos/SystemStatus.dto.ts: -------------------------------------------------------------------------------- 1 | export interface SystemStatus { 2 | currentBufferNumber: number; 3 | latestAvailableRoundId: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/main.ts: -------------------------------------------------------------------------------- 1 | import { runMonitorserver } from "./monitorserver"; 2 | 3 | runMonitorserver(); 4 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/monitor-server.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { CommonModule } from "../../common/src"; 3 | import { PrometheusController } from "./controllers/prometheus.controller"; 4 | import { PrometheusEngineService } from "./services/prometheus-engine.service"; 5 | import { ServerConfigurationService } from "./services/server-configuration.service"; 6 | 7 | @Module({ 8 | imports: [CommonModule], 9 | controllers: [PrometheusController], 10 | providers: [ 11 | { 12 | provide: "SERVER_CONFIG", 13 | useFactory: async () => { 14 | const config = new ServerConfigurationService(); 15 | await config.initialize(); 16 | return config; 17 | }, 18 | }, 19 | PrometheusEngineService, 20 | ], 21 | }) 22 | export class MonitorServerModule {} 23 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/monitorserver.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from "@nestjs/core"; 2 | import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; 3 | import helmet from "helmet"; 4 | import { getGlobalLogger } from "../../../utils/logging/logger"; 5 | import { MonitorServerModule } from "./monitor-server.module"; 6 | import { ServerConfigurationService } from "./services/server-configuration.service"; 7 | 8 | export async function runMonitorserver() { 9 | const app = await NestFactory.create(MonitorServerModule); 10 | 11 | app.use(helmet()); 12 | 13 | app.setGlobalPrefix(process.env.APP_BASE_PATH ?? ""); 14 | const config = new DocumentBuilder() 15 | .setTitle("Attestation Suite Prometheus Monitor Server") 16 | .setBasePath(process.env.APP_BASE_PATH ?? "") 17 | .setDescription("Public server for Attestation Suite Prometheus Monitor metrics.") 18 | .setVersion("1.0") 19 | .build(); 20 | const document = SwaggerModule.createDocument(app, config); 21 | SwaggerModule.setup(`${process.env.APP_BASE_PATH ? process.env.APP_BASE_PATH + "/" : ""}api-doc`, app, document); 22 | 23 | const logger = getGlobalLogger("web"); 24 | const configurationService = app.get("SERVER_CONFIG") as ServerConfigurationService; 25 | 26 | let port = configurationService.serverCredentials.prometheus.monitorServerPort; 27 | await app.listen(port, "0.0.0.0", () => 28 | // tslint:disable-next-line:no-console 29 | logger.info(`Server started listening at http://0.0.0.0:${configurationService.serverCredentials.prometheus.monitorServerPort}`) 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/servers/monitor-server/src/services/server-configuration.service.ts: -------------------------------------------------------------------------------- 1 | import { MonitorConfig } from "../../../../monitor/MonitorConfiguration"; 2 | import { readSecureConfig } from "../../../../utils/config/configSecure"; 3 | 4 | export class ServerConfigurationService { 5 | serverCredentials: MonitorConfig; 6 | _initialized = false; 7 | 8 | constructor() {} 9 | 10 | async initialize() { 11 | if (this._initialized) return; 12 | this.serverCredentials = await readSecureConfig(new MonitorConfig(), "monitor"); 13 | this._initialized = true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/servers/monitor-server/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "experimentalDecorators": true, 6 | "outDir": "../../../dist/src/servers/monitor-server" 7 | }, 8 | "include": ["src/**/*"], 9 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/auth/auth-header-api-key.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, UnauthorizedException } from "@nestjs/common"; 2 | import { PassportStrategy } from "@nestjs/passport"; 3 | import Strategy from "passport-headerapikey"; 4 | import { VerifierConfigurationService } from "../services/verifier-configuration.service"; 5 | 6 | @Injectable() 7 | export class HeaderApiKeyStrategy extends PassportStrategy(Strategy, "api-key") { 8 | constructor(@Inject("VERIFIER_CONFIG") private config: VerifierConfigurationService) { 9 | super({ header: "X-API-KEY", prefix: "" }, true, async (apiKey, done) => { 10 | return this.validate(apiKey, done); 11 | }); 12 | } 13 | 14 | public validate(apiKey: string, done: (error: Error, data) => {}) { 15 | if (this.config?.config?.apiKeys?.find((x) => x.apiKey === apiKey)) { 16 | done(null, true); 17 | } 18 | done(new UnauthorizedException(), null); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/config-models/ServerUser.ts: -------------------------------------------------------------------------------- 1 | import { optional } from "@flarenetwork/mcc"; 2 | 3 | export class ServerUser { 4 | name: string = ""; 5 | apiKey: string = ""; 6 | @optional() ip: string = ""; 7 | } 8 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/dtos/indexer/ApiDbBlock.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Block header data in the indexer database 3 | */ 4 | export class ApiDBBlock { 5 | /** 6 | * Block hash 7 | */ 8 | blockHash: string; 9 | /** 10 | * Block number 11 | */ 12 | blockNumber: number; 13 | /** 14 | * Block timestamp in seconds 15 | */ 16 | timestamp: number; 17 | /** 18 | * Number of transactions in the block. 19 | */ 20 | transactions?: number; 21 | 22 | /** 23 | * Whether the block is confirmed. 24 | */ 25 | confirmed?: boolean; 26 | 27 | /** 28 | * Number of confirmations of the block. 29 | */ 30 | numberOfConfirmations: number; 31 | 32 | /** 33 | * Parent block hash. 34 | */ 35 | previousBlockHash: string; 36 | } 37 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/dtos/indexer/ApiDbState.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * State table entry of the indexer database 3 | */ 4 | export class ApiDBState { 5 | /** 6 | * Entry name (key) 7 | */ 8 | name: string; 9 | /** 10 | * String value of the entry 11 | */ 12 | valueString?: string; 13 | 14 | /** 15 | * Number value of the entry 16 | */ 17 | valueNumber?: number; 18 | 19 | /** 20 | * Timestamp of the last change of the entry. 21 | */ 22 | timestamp: number; 23 | 24 | /** 25 | * Comment for entry (optional). 26 | */ 27 | comment?: string; 28 | } 29 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/dtos/indexer/ApiDbTransaction.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Confirmed transaction entry in the indexer database. 3 | */ 4 | export class ApiDBTransaction { 5 | /** 6 | * Entry id in the database. 7 | */ 8 | id: number; 9 | /** 10 | * Chain type as number. 11 | */ 12 | chainType: number; 13 | 14 | /** 15 | * Transaction id 16 | */ 17 | transactionId: string; 18 | 19 | /** 20 | * Block number of the transaction 21 | */ 22 | blockNumber: number = 0; 23 | 24 | /** 25 | * Block timestamp of the transaction. 26 | */ 27 | timestamp: number; 28 | 29 | /** 30 | * Payment reference of the transaction. 31 | */ 32 | paymentReference: string; 33 | 34 | /** 35 | * Validator node API response for transaction description. For UTXO chains additional information may be embedded into response. 36 | */ 37 | response: string | any = ""; 38 | 39 | /** 40 | * True if it is native payment. 41 | */ 42 | isNativePayment: boolean; 43 | 44 | /** 45 | * Transaction type (depends on chain) 46 | */ 47 | transactionType: string; 48 | } 49 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/dtos/indexer/BlockRange.dto.ts: -------------------------------------------------------------------------------- 1 | export class BlockRange { 2 | /** 3 | * First block number (included) 4 | */ 5 | first: number; 6 | /** 7 | * Last block number (included) 8 | */ 9 | last: number; 10 | } 11 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/dtos/indexer/QueryTransaction.dto.ts: -------------------------------------------------------------------------------- 1 | import { Transform, Type } from "class-transformer"; 2 | import { IsInt, IsOptional } from "class-validator"; 3 | 4 | /** 5 | * Query parameters for listing transactions from indexer database. 6 | */ 7 | export class QueryTransaction { 8 | /** 9 | * Minimal block number of query range 10 | */ 11 | @IsInt() 12 | @Type(() => Number) 13 | @IsOptional() 14 | from?: number; 15 | /** 16 | * Maximal block number of the query range 17 | */ 18 | @IsInt() 19 | @Type(() => Number) 20 | @IsOptional() 21 | to?: number; 22 | /** 23 | * 0x-prefixed lowercase hex string representing 32-bytes 24 | */ 25 | @IsOptional() 26 | paymentReference?: string; 27 | /** 28 | * Query limit. Capped by server config settings 29 | */ 30 | @IsInt() 31 | @Type(() => Number) 32 | @IsOptional() 33 | limit?: number; 34 | /** 35 | * Query offset 36 | */ 37 | @IsInt() 38 | @Type(() => Number) 39 | @IsOptional() 40 | offset?: number; 41 | /** 42 | * Whether response from node stored in the indexer database should be returned 43 | */ 44 | @Transform(({ value }) => value === "true") 45 | @IsOptional() 46 | returnResponse?: boolean; 47 | } 48 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/main.ts: -------------------------------------------------------------------------------- 1 | import { runVerifierServer } from "./verifierServer"; 2 | 3 | void runVerifierServer(); 4 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/services/verifier-processors/btc-processor.service.ts: -------------------------------------------------------------------------------- 1 | import { ChainType, MCC, UtxoMccCreate } from "@flarenetwork/mcc"; 2 | import { EntityManager } from "typeorm"; 3 | import { IIndexedQueryManager } from "../../../../../indexed-query-manager/IIndexedQueryManager"; 4 | import { IndexedQueryManager } from "../../../../../indexed-query-manager/IndexedQueryManager"; 5 | import { IndexedQueryManagerOptions } from "../../../../../indexed-query-manager/indexed-query-manager-types"; 6 | import { VerifierConfigurationService } from "../verifier-configuration.service"; 7 | 8 | export class BTCProcessorService { 9 | client: MCC.BTC; 10 | indexedQueryManager: IIndexedQueryManager; 11 | 12 | constructor(private config: VerifierConfigurationService, private manager: EntityManager) { 13 | this.client = new MCC.BTC(this.config.config.chainConfiguration.mccCreate as UtxoMccCreate); 14 | 15 | const options: IndexedQueryManagerOptions = { 16 | chainType: ChainType.BTC, 17 | entityManager: this.manager, 18 | numberOfConfirmations: () => { 19 | return this.config.config.chainConfiguration.numberOfConfirmations; 20 | }, 21 | }; 22 | 23 | this.indexedQueryManager = new IndexedQueryManager(options); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/services/verifier-processors/doge-processor.service.ts: -------------------------------------------------------------------------------- 1 | import { ChainType, MCC, UtxoMccCreate } from "@flarenetwork/mcc"; 2 | import { EntityManager } from "typeorm"; 3 | import { DogeIndexedQueryManager } from "../../../../../indexed-query-manager/DogeIndexQueryManager"; 4 | import { IIndexedQueryManager } from "../../../../../indexed-query-manager/IIndexedQueryManager"; 5 | import { IndexedQueryManagerOptions } from "../../../../../indexed-query-manager/indexed-query-manager-types"; 6 | import { ExternalDBVerifierConfigurationService } from "../verifier-configuration.service"; 7 | 8 | export class DOGEProcessorService { 9 | client: MCC.DOGE; 10 | indexedQueryManager: IIndexedQueryManager; 11 | 12 | constructor(private config: ExternalDBVerifierConfigurationService, private manager: EntityManager) { 13 | this.client = new MCC.DOGE(this.config.config.chainConfiguration.mccCreate as UtxoMccCreate); 14 | 15 | const options: IndexedQueryManagerOptions = { 16 | chainType: ChainType.DOGE, 17 | entityManager: this.manager, 18 | numberOfConfirmations: () => { 19 | return this.config.config.chainConfiguration.numberOfConfirmations; 20 | }, 21 | }; 22 | 23 | this.indexedQueryManager = new DogeIndexedQueryManager(options); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/services/verifier-processors/xrp-processor.service.ts: -------------------------------------------------------------------------------- 1 | import { ChainType, MCC, XrpMccCreate } from "@flarenetwork/mcc"; 2 | import { EntityManager } from "typeorm"; 3 | import { IndexedQueryManager } from "../../../../../indexed-query-manager/IndexedQueryManager"; 4 | import { IndexedQueryManagerOptions } from "../../../../../indexed-query-manager/indexed-query-manager-types"; 5 | import { VerifierConfigurationService } from "../verifier-configuration.service"; 6 | import { IIndexedQueryManager } from "../../../../../indexed-query-manager/IIndexedQueryManager"; 7 | 8 | export class XRPProcessorService { 9 | client: MCC.XRP; 10 | indexedQueryManager: IIndexedQueryManager; 11 | 12 | constructor(private config: VerifierConfigurationService, private manager: EntityManager) { 13 | this.client = new MCC.XRP(this.config.config.chainConfiguration.mccCreate as XrpMccCreate); 14 | 15 | const options: IndexedQueryManagerOptions = { 16 | chainType: ChainType.XRP, 17 | entityManager: this.manager, 18 | numberOfConfirmations: () => { 19 | return this.config.config.chainConfiguration.numberOfConfirmations; 20 | }, 21 | }; 22 | 23 | this.indexedQueryManager = new IndexedQueryManager(options); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/utils/validators/Hash32Validator.ts: -------------------------------------------------------------------------------- 1 | import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from "class-validator"; 2 | 3 | /** 4 | * Validator constraint if the given value is a 0x-prefixed hexadecimal string representing 32 bytes. 5 | */ 6 | @ValidatorConstraint({ name: "hash-32", async: false }) 7 | export class IsHash32 implements ValidatorConstraintInterface { 8 | /** 9 | * Validates if the given value is a 0x-prefixed hexadecimal string representing 32 bytes. 10 | * @param text 11 | * @param args 12 | * @returns 13 | */ 14 | validate(text: any, args: ValidationArguments) { 15 | return typeof text === "string" && /^0x[0-9a-f]{64}$/i.test(text); 16 | } 17 | 18 | /** 19 | * Returns the default error message template. 20 | * @param args 21 | * @returns 22 | */ 23 | defaultMessage(args: ValidationArguments) { 24 | return "($property) value ($value) is not 0x-prefixed hexadecimal string representing 32 bytes"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/utils/validators/NumberLikeValidator.ts: -------------------------------------------------------------------------------- 1 | import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from "class-validator"; 2 | 3 | /** 4 | * Validator constraint if the given value is a number or 0x-prefixed hexadecimal string. 5 | */ 6 | @ValidatorConstraint({ name: "string-or-number", async: false }) 7 | export class IsNumberLike implements ValidatorConstraintInterface { 8 | /** 9 | * Validates if the given value is a number or 0x-prefixed hexadecimal string. 10 | * @param text 11 | * @param args 12 | * @returns 13 | */ 14 | validate(text: any, args: ValidationArguments) { 15 | return typeof text === "number" || (typeof text === "string" && /^0x[0-9a-f]+$/i.test(text)); 16 | } 17 | 18 | /** 19 | * Returns the default error message template. 20 | * @param args 21 | * @returns 22 | */ 23 | defaultMessage(args: ValidationArguments) { 24 | return "($property) value ($value) is not number or 0x-prefixed hexadecimal string"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/servers/verifier-server/src/verification/address-validity.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/src/servers/verifier-server/src/verification/address-validity.ts -------------------------------------------------------------------------------- /src/servers/verifier-server/src/verification/address-validity/utils.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from "crypto"; 2 | import { AddressValidity_ResponseBody } from "../../dtos/attestation-types/AddressValidity.dto"; 3 | import { ZERO_BYTES_32 } from "../../../../../external-libs/utils"; 4 | import { standardAddressHash } from "@flarenetwork/mcc"; 5 | 6 | export function base58Checksum(decodedAddress: Buffer): boolean { 7 | const preChecksum = decodedAddress.subarray(-4); 8 | const hash1 = createHash("sha256").update(decodedAddress.subarray(0, -4)).digest(); 9 | const hash2 = createHash("sha256").update(hash1).digest(); 10 | const newChecksum = hash2.subarray(0, 4); 11 | return preChecksum.equals(newChecksum); 12 | } 13 | 14 | export const INVALID_ADDRESS_RESPONSE: AddressValidity_ResponseBody = { 15 | isValid: false, 16 | standardAddress: "", 17 | standardAddressHash: ZERO_BYTES_32, 18 | }; 19 | 20 | export function validAddressToResponse(address: string, lowercase: boolean): AddressValidity_ResponseBody { 21 | const standardAddress = lowercase ? address.toLowerCase() : address; 22 | return { isValid: true, standardAddress: standardAddress, standardAddressHash: standardAddressHash(standardAddress) }; 23 | } 24 | -------------------------------------------------------------------------------- /src/servers/verifier-server/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../../dist/src/servers/verifier-server" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /src/servers/web-server/src/config-models/WebserverConfig.ts: -------------------------------------------------------------------------------- 1 | import { optional } from "@flarenetwork/mcc"; 2 | import { DatabaseConnectOptions } from "../../../../utils/database/DatabaseConnectOptions"; 3 | import { AdditionalTypeInfo, IReflection } from "../../../../utils/reflection/reflection"; 4 | 5 | export class WebserverConfig implements IReflection { 6 | public firstEpochStartTime: number = 1636070400; 7 | 8 | // voting round duration in sec 9 | public roundDurationSec: number = 90; 10 | 11 | // path to service status file on server 12 | @optional() public serviceStatusFilePath: string = ""; 13 | 14 | port: number = 9500; 15 | 16 | attesterDatabase = new DatabaseConnectOptions(); 17 | 18 | instantiate(): WebserverConfig { 19 | return new WebserverConfig(); 20 | } 21 | getAdditionalTypeInfo(obj: any): AdditionalTypeInfo { 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/servers/web-server/src/dtos/SpecificProofRequest.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsHexadecimal, IsInt } from "class-validator"; 2 | 3 | /** 4 | * Attestation request data. 5 | */ 6 | export class SpecificProofRequest { 7 | /** 8 | * Round of the attestation request submission 9 | */ 10 | @IsInt() 11 | roundId: number; 12 | /** 13 | * Attestation request data as submitted to State Connector smart contract 14 | */ 15 | @IsHexadecimal() 16 | requestBytes: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/servers/web-server/src/dtos/SystemStatus.dto.ts: -------------------------------------------------------------------------------- 1 | export class SystemStatus { 2 | currentBufferNumber: number; 3 | latestAvailableRoundId: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/servers/web-server/src/dtos/VotingRoundRequest.dto.ts: -------------------------------------------------------------------------------- 1 | export class VotingRoundRequest { 2 | roundId: number; 3 | requestBytes: string; 4 | verificationStatus: string; 5 | attestationStatus?: string; 6 | exceptionError?: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/servers/web-server/src/dtos/VotingRoundResult.dto.ts: -------------------------------------------------------------------------------- 1 | 2 | export class VotingRoundResult { 3 | roundId: number; 4 | hash: string; 5 | requestBytes: string; 6 | request: any; 7 | response: any; 8 | merkleProof: string[]; 9 | } 10 | -------------------------------------------------------------------------------- /src/servers/web-server/src/main.ts: -------------------------------------------------------------------------------- 1 | import { runWebserver } from "./webserver"; 2 | 3 | void runWebserver(); 4 | -------------------------------------------------------------------------------- /src/servers/web-server/src/services/server-configuration.service.ts: -------------------------------------------------------------------------------- 1 | import { readSecureConfig } from "../../../../utils/config/configSecure"; 2 | import { EpochSettings } from "../../../../utils/data-structures/EpochSettings"; 3 | import { WebserverConfig } from "../config-models/WebserverConfig"; 4 | 5 | export class ServerConfigurationService { 6 | serverCredentials: WebserverConfig; 7 | epochSettings: EpochSettings; 8 | _initialized = false; 9 | constructor() {} 10 | 11 | async initialize() { 12 | if (this._initialized) return; 13 | this.serverCredentials = await readSecureConfig(new WebserverConfig(), "webserver"); 14 | this.epochSettings = new EpochSettings(BigInt(this.serverCredentials.firstEpochStartTime), BigInt(this.serverCredentials.roundDurationSec)); 15 | this._initialized = true; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/servers/web-server/src/web-server.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { TypeOrmModule } from "@nestjs/typeorm"; 3 | import { attesterEntities } from "../../../utils/database/databaseEntities"; 4 | import { CommonModule } from "../../common/src"; 5 | import { ProofController } from "./controllers/proof.controller"; 6 | import { ProofEngineService } from "./services/proof-engine.service"; 7 | import { ServerConfigurationService } from "./services/server-configuration.service"; 8 | import { createTypeOrmOptions } from "./utils/db-config"; 9 | 10 | @Module({ 11 | imports: [ 12 | CommonModule, 13 | TypeOrmModule.forRootAsync({ 14 | name: "attesterDatabase", 15 | useFactory: async () => createTypeOrmOptions("web", attesterEntities()), 16 | }), 17 | ], 18 | controllers: [ProofController], 19 | providers: [ 20 | { 21 | provide: "SERVER_CONFIG", 22 | useFactory: async () => { 23 | const config = new ServerConfigurationService(); 24 | await config.initialize(); 25 | return config; 26 | }, 27 | }, 28 | ProofEngineService, 29 | ], 30 | }) 31 | export class WebServerModule {} 32 | -------------------------------------------------------------------------------- /src/servers/web-server/src/webserver.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from "@nestjs/common"; 2 | import { NestFactory } from "@nestjs/core"; 3 | import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; 4 | import helmet from "helmet"; 5 | import { getGlobalLogger } from "../../../utils/logging/logger"; 6 | import { ServerConfigurationService } from "./services/server-configuration.service"; 7 | import { WebServerModule } from "./web-server.module"; 8 | 9 | export async function runWebserver() { 10 | const app = await NestFactory.create(WebServerModule); 11 | 12 | app.use(helmet()); 13 | app.useGlobalPipes(new ValidationPipe({ transform: true })); 14 | app.enableCors(); 15 | 16 | app.setGlobalPrefix(process.env.APP_BASE_PATH ?? ""); 17 | const config = new DocumentBuilder() 18 | .setTitle("Attestation Client Public Server") 19 | .setBasePath(process.env.APP_BASE_PATH ?? "") 20 | .setDescription("Public server for attestation client providing data about attestations by round, and attestation status metrics.") 21 | .setVersion("1.0") 22 | .build(); 23 | const document = SwaggerModule.createDocument(app, config); 24 | SwaggerModule.setup(`${process.env.APP_BASE_PATH ? process.env.APP_BASE_PATH + "/" : ""}api-doc`, app, document); 25 | 26 | const logger = getGlobalLogger("web"); 27 | const configurationService = app.get("SERVER_CONFIG") as ServerConfigurationService; 28 | 29 | let port = configurationService.serverCredentials.port; 30 | await app.listen(port, "0.0.0.0", () => logger.info(`Server started listening at http://0.0.0.0:${configurationService.serverCredentials.port}`)); 31 | } 32 | -------------------------------------------------------------------------------- /src/servers/web-server/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../../dist/src/servers/web-server" 6 | }, 7 | "include": ["src/**/*", "../../entity/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /src/spammer/README.md: -------------------------------------------------------------------------------- 1 | # Spammer 2 | 3 | This folder contains spammer functionality for testing attestation system. Spammer generated verifiable or fake attestation request randomly. This is not a critical part of code in operation of the attestation client and does not need to be audited. -------------------------------------------------------------------------------- /src/state-collector-finalizer/main.ts: -------------------------------------------------------------------------------- 1 | import { runBot } from "./state-connector-validator-bot"; 2 | import * as yargs from "yargs"; 3 | 4 | const args = yargs 5 | .scriptName("airdropTransactions") 6 | .option("a", { 7 | alias: "state-connector-address", 8 | describe: "State connector temp address", 9 | demandOption: "Provide the address of state connector temp contract address", 10 | type: "string", 11 | nargs: 1, 12 | }) 13 | .option("r", { 14 | alias: "rpc", 15 | describe: "Rpc url", 16 | demandOption: "Provide rpc url", 17 | type: "string", 18 | nargs: 1, 19 | }) 20 | .option("f", { 21 | alias: "flavor", 22 | describe: "Which flavor of stateconn to deploy", 23 | default: "temp", 24 | choices: ["temp", "tran"], 25 | type: "string", 26 | nargs: 1, 27 | }).argv; 28 | 29 | const { stateConnectorAddress, rpc, flavor } = args as any; 30 | 31 | runBot(stateConnectorAddress, rpc, flavor) 32 | .then(() => process.exit(0)) 33 | .catch((error) => { 34 | console.error(error); 35 | process.exit(1); 36 | }); 37 | -------------------------------------------------------------------------------- /src/utils/compression/compression.zlib.ts: -------------------------------------------------------------------------------- 1 | import * as zlib from "zlib"; 2 | 3 | /** 4 | * Compress string data into base64 string. 5 | * @param data 6 | * @returns compressed data as base64 string 7 | */ 8 | export function compressGzip(data: string): string { 9 | return zlib.deflateSync(data, { level: 9 }).toString('base64'); 10 | } 11 | 12 | /** 13 | * Decompress base64 string compressed with @Compress function back into source string. 14 | * @param compressedData base64 string compressed with @Compress function 15 | * @returns decompressed data as string 16 | */ 17 | export function decompressGzip(compressedData: string): string { 18 | return zlib.inflateSync(new Buffer(compressedData, 'base64')).toString(); 19 | } 20 | 21 | /** 22 | * Compress string data into binary buffer. 23 | * @param data 24 | * @returns compressed data as binary buffer 25 | */ 26 | export function compressGzipBin(data: string): Buffer { 27 | //return zlib.deflateSync(data, {level: 9}); 28 | return zlib.gzipSync(data, { level: 9 }); 29 | //return zlib.brotliCompressSync(data); 30 | } 31 | 32 | /** 33 | * Decompress binary buffer compressed with @CompressBin function back into source string. 34 | * @param compressedDataBuffer binary data compressed with @CompressBin function 35 | * @returns decompressed data string 36 | */ 37 | export function decompressGzipBin(compressedDataBuffer: Buffer): string { 38 | //return zlib.inflateSync(compressedDataBuffer).toString(); 39 | return zlib.gunzipSync(compressedDataBuffer).toString(); 40 | //return zlib.brotliDecompressSync(compressedDataBuffer).toString(); 41 | } 42 | -------------------------------------------------------------------------------- /src/utils/data-structures/Queue.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple and efficient implementation of a queue suitable for larger sizes 3 | */ 4 | export class Queue { 5 | private data: { [key: number]: T } = {}; 6 | private head = 0; // first index 7 | private tail = 0; // first empty index 8 | 9 | /** 10 | * Add an @param item to the end of the queue 11 | */ 12 | public push(item: T): void { 13 | this.data[this.tail] = item; 14 | this.tail++; 15 | } 16 | 17 | /** 18 | * Add an @param item to the beginning of the queue 19 | */ 20 | public prepend(item: T): void { 21 | this.data[this.head - 1] = item; 22 | this.head--; 23 | } 24 | 25 | // Can be called only if head < tail 26 | public shift(): T { 27 | const item = this.first; 28 | delete this.data[this.head]; 29 | this.head++; 30 | return item; 31 | } 32 | 33 | public get size() { 34 | return this.tail - this.head; 35 | } 36 | 37 | /** 38 | * Return the first element in the queue 39 | */ 40 | public get first(): T { 41 | if (this.size > 0) { 42 | return this.data[this.head]; 43 | } 44 | throw Error("Empty queue"); 45 | } 46 | 47 | /** 48 | * Clears the queue 49 | */ 50 | public destroy() { 51 | delete this.data; 52 | this.data = {}; 53 | this.tail = 0; 54 | this.head = 0; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/utils/helpers/crypto-utils.ts: -------------------------------------------------------------------------------- 1 | import Web3 from "web3"; 2 | 3 | /** 4 | * Returns crypto safe 32-byte random hex string using web3.js generator 5 | * @returns Random 32-byte string 6 | */ 7 | 8 | export async function getCryptoSafeRandom(length = 32) { 9 | return Web3.utils.randomHex(length); 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/helpers/internetTime.ts: -------------------------------------------------------------------------------- 1 | const timeSync = 0; 2 | 3 | /** 4 | * Returns time passed from 1 January 1970 in milliseconds, UTC 5 | * @returns 6 | */ 7 | export function getTimeMs() { 8 | const now = new Date().getTime(); 9 | // Test purposes only 10 | if (process.env.NODE_ENV === "development") { 11 | if (process.env.TEST_OFFSET_TIME_MS) { 12 | const offset = parseInt("" + process.env.TEST_OFFSET_TIME_MS, 10); 13 | return now + offset * 1000; 14 | } 15 | if (process.env.TEST_SCHEDULER_TIME_MS) { 16 | return parseInt("" + process.env.TEST_SCHEDULER_TIME_MS, 10); 17 | } 18 | } 19 | 20 | return Math.round(now + timeSync); 21 | } 22 | 23 | /** 24 | * Returns time passed from 1 January 1970 in seconds, UTC 25 | * @returns 26 | */ 27 | export function getTimeSec() { 28 | return Math.floor(getTimeMs() / 1000); 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/helpers/promiseRequestTypes.ts: -------------------------------------------------------------------------------- 1 | export enum PromiseRequestStatus { 2 | initialized, 3 | pending, 4 | rejected, 5 | resolved, 6 | } 7 | 8 | export interface IIdentifiable { 9 | id?: string; 10 | } 11 | 12 | export type WsResponseStatus = "OK" | "ERROR"; 13 | 14 | export interface IIdentifiableResponse { 15 | data: S; 16 | status: WsResponseStatus; 17 | errorMessage?: string; 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/logging/testLogger.ts: -------------------------------------------------------------------------------- 1 | import Transport from "winston-transport"; 2 | export class TestLogger extends Transport { 3 | constructor() { 4 | super(); 5 | } 6 | 7 | static logs = []; 8 | 9 | static displayLog = 0; 10 | 11 | static setDisplay(display = 0) { 12 | TestLogger.displayLog = display; 13 | } 14 | 15 | static clear() { 16 | TestLogger.logs = []; 17 | } 18 | static exists(text: string): boolean { 19 | // optimize search if it becomes too slow 20 | for (const logText of TestLogger.logs) { 21 | if (logText === text) return true; 22 | } 23 | 24 | return false; 25 | } 26 | 27 | log = (info: any, callback: any) => { 28 | setImmediate(() => this.emit("logged", info)); 29 | 30 | if (info.message) { 31 | const text = info.message.toString(); 32 | 33 | TestLogger.logs.push(text); 34 | 35 | switch (TestLogger.displayLog) { 36 | // raw console output 37 | case 1: 38 | console.log(text); 39 | break; 40 | case 2: 41 | console.log(text); 42 | break; 43 | } 44 | } 45 | 46 | if (callback) { 47 | callback(); 48 | } 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /src/utils/monitoring/EServiceStatus.ts: -------------------------------------------------------------------------------- 1 | export enum EServiceStatus { 2 | unknown, 3 | active, 4 | inactive, 5 | failed, 6 | invalid, 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/reflection/IInstantiate.ts: -------------------------------------------------------------------------------- 1 | export interface IInstantiate { 2 | instantiate(): T; 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/reflection/reflection.ts: -------------------------------------------------------------------------------- 1 | import { IInstantiate } from "./IInstantiate"; 2 | 3 | export class AdditionalTypeInfo { 4 | arrayMap = new Map(); 5 | additionalKeys = new Map(); 6 | 7 | getArrayType(name: string) { 8 | return this.arrayMap.get(name); 9 | } 10 | } 11 | 12 | export interface IReflection extends IInstantiate { 13 | instantiate(): T; 14 | getAdditionalTypeInfo(obj: any): AdditionalTypeInfo; 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/security/encrypt.ts: -------------------------------------------------------------------------------- 1 | import crypto from "crypto"; 2 | 3 | /** 4 | * Encrypt string using AES256. 5 | * @param password 6 | * @param text 7 | * @returns 8 | */ 9 | export function encryptString(password: string, text: string): string { 10 | // const passwordHash = crypto.createHash("sha256").update(password, "ascii").digest(); 11 | const passwordHash = crypto.scryptSync(password, "Flare", 32, { N: 65536, maxmem: 134217728 }); 12 | const initVector = crypto.randomBytes(16); 13 | const cipher = crypto.createCipheriv("aes-256-gcm", passwordHash, initVector); 14 | const encbuf = cipher.update(text, "utf-8"); 15 | return Buffer.concat([initVector, encbuf]).toString("base64"); 16 | } 17 | 18 | /** 19 | * Decrypt string using AES256. 20 | * @param password 21 | * @param encryptedText 22 | * @returns 23 | */ 24 | export function decryptString(password: string, encryptedText: string): string { 25 | // const passwordHash = crypto.createHash("sha256").update(password, "ascii").digest(); 26 | const passwordHash = crypto.scryptSync(password, "Flare", 32, { N: 65536, maxmem: 134217728 }); 27 | 28 | const encIvBuf = Buffer.from(encryptedText, "base64"); 29 | const initVector = encIvBuf.subarray(0, 16); 30 | const encBuf = encIvBuf.subarray(16); 31 | const cipher = crypto.createDecipheriv("aes-256-gcm", passwordHash, initVector); 32 | return cipher.update(encBuf).toString("utf-8"); 33 | } 34 | -------------------------------------------------------------------------------- /src/verification/attestation-types/attestation-types-helpers.ts: -------------------------------------------------------------------------------- 1 | import BN from "bn.js"; 2 | import Web3 from "web3"; 3 | import { WeightedRandomChoice } from "./attestation-types"; 4 | 5 | /** 6 | * Returns the random element of the list 7 | * @param list 8 | * @returns the random element 9 | */ 10 | export function randomListElement(list: T[]): T | undefined { 11 | const randN = Math.floor(Math.random() * list.length); 12 | return list[randN]; 13 | } 14 | 15 | /** 16 | * Returns the random element of the list of weighted choices 17 | * @param choices list of weighted choices 18 | * @returns random value (name) of the selected weighted choice 19 | */ 20 | export function randomWeightedChoice(choices: WeightedRandomChoice[]): T { 21 | const weightSum = choices.map((choice) => choice.weight).reduce((a, b) => a + b); 22 | const randSum = Math.floor(Math.random() * (weightSum + 1)); 23 | let tmpSum = 0; 24 | for (const choice of choices) { 25 | tmpSum += choice.weight; 26 | if (tmpSum >= randSum) return choice.name; 27 | } 28 | return choices[choices.length - 1].name; 29 | } 30 | 31 | 32 | /** 33 | * Converts objects to Hex value (optionally left padded) 34 | * @param x input object 35 | * @param padToBytes places to (left) pad to (optional) 36 | * @returns (padded) hex valu 37 | */ 38 | export function toHex(x: string | number | BN, padToBytes?: number) { 39 | if ((padToBytes as any) > 0) { 40 | return Web3.utils.leftPad(Web3.utils.toHex(x), padToBytes! * 2); 41 | } 42 | return Web3.utils.toHex(x); 43 | } 44 | -------------------------------------------------------------------------------- /src/verification/routing/configs/VerifierAttestationTypeRouteConfig.ts: -------------------------------------------------------------------------------- 1 | import { AdditionalTypeInfo, IReflection } from "../../../utils/reflection/reflection"; 2 | /** 3 | * Configuration for verifier routes for a specific attestation type 4 | */ 5 | export class VerifierAttestationTypeRouteConfig implements IReflection { 6 | /** 7 | * A list of attestation types indicated by their names. Names in type definition files in folder 8 | * `src/verification/attestation-types` 9 | * should be used. 10 | */ 11 | public attestationTypes: string[] = []; 12 | /** 13 | * URL for the verifier server to serve the attestation type 14 | */ 15 | public url: string = ""; 16 | /** 17 | * API key for the verifier server. 18 | */ 19 | public apiKey: string = ""; 20 | 21 | instantiate(): VerifierAttestationTypeRouteConfig { 22 | return new VerifierAttestationTypeRouteConfig(); 23 | } 24 | 25 | getAdditionalTypeInfo(obj: any): AdditionalTypeInfo { 26 | const info = new AdditionalTypeInfo(); 27 | info.arrayMap.set("attestationTypes", "string"); 28 | return info; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/attestationClient/attestationData.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, expect } from "chai"; 2 | import { AttestationData } from "../../src/attester/AttestationData"; 3 | import { AttestationDefinitionStore } from "../../src/external-libs/AttestationDefinitionStore"; 4 | import { initializeTestGlobalLogger } from "../../src/utils/logging/logger"; 5 | import { AttestationRequest } from "../../typechain-web3-v1/StateConnector"; 6 | import { createBlankAtRequestEvent } from "../attestationClient/utils/createEvents"; 7 | import { getTestFile } from "../test-utils/test-utils"; 8 | import { ethers } from "ethers"; 9 | 10 | describe(`Attestation Data (${getTestFile(__filename)})`, function () { 11 | initializeTestGlobalLogger(); 12 | let defStore: AttestationDefinitionStore; 13 | let event: AttestationRequest; 14 | let attData: AttestationData; 15 | 16 | before(async function () { 17 | defStore = new AttestationDefinitionStore("configs/type-definitions"); 18 | event = createBlankAtRequestEvent(defStore, "Payment", "XRP", 1, ethers.zeroPadBytes("0x0123aa", 32), "123", ethers.zeroPadBytes("0x1d1d1d", 32)); 19 | }); 20 | 21 | it("Should construct Attestation Data", function () { 22 | attData = new AttestationData(event); 23 | assert(attData); 24 | }); 25 | 26 | it("Should get id", function () { 27 | const res = attData.getId(); 28 | expect(res).to.eq(event.returnValues.data); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/attestationClient/bitVoteData.test.ts: -------------------------------------------------------------------------------- 1 | // yarn test test/attestationClient/bitVoteData.test.ts 2 | 3 | import { expect, assert } from "chai"; 4 | import { BitVoteData } from "../../src/attester/BitVoteData"; 5 | import { getTestFile } from "../test-utils/test-utils"; 6 | import { createBlankBitVoteEvent } from "./utils/createEvents"; 7 | 8 | describe(`bitVote Data (${getTestFile(__filename)})`, function () { 9 | const bitVote = "0x05fakeBitVote"; 10 | 11 | const event = createBlankBitVoteEvent(bitVote); 12 | 13 | const bitVoteData = new BitVoteData(event); 14 | 15 | it("Should construct bitVoteData", function () { 16 | assert(bitVoteData); 17 | }); 18 | 19 | it("Should get bitVote", function () { 20 | expect(bitVoteData.bitVote).to.eq("0xfakeBitVote"); 21 | }); 22 | 23 | it("Should roundCheck", function () { 24 | const res = bitVoteData.roundCheck(261); 25 | assert(res); 26 | }); 27 | 28 | it("Should throw error if to short bit vote", function () { 29 | const bitVote = "0x1"; 30 | const event = createBlankBitVoteEvent(bitVote); 31 | expect(() => new BitVoteData(event)).to.throw("Incorrect bit vote"); 32 | }); 33 | 34 | it("Should create empty data", function () { 35 | const data = new BitVoteData(undefined); 36 | assert(data); 37 | 38 | const res = data.bitVote; 39 | expect(res).to.eq("0x00"); 40 | 41 | assert(!data.roundCheck(123)); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/global-configs/global-0-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId": 0, 3 | "defaultSetAssignerAddresses": [ 4 | "0xead9c93b79ae7c1591b1fb5323bd777e86e150d4", 5 | "0xe5904695748fe4a84b40b3fc79de2277660bd1d3", 6 | "0x92561f28ec438ee9831d00d1d59fbdc981b762b2", 7 | "0x2ffd013aaa7b5a7da93336c2251075202b33fb2b", 8 | "0x9fc9c2dfba3b6cf204c37a5f690619772b926e39", 9 | "0xfbc51a9582d031f2ceaad3959256596c5d3a5468", 10 | "0x84fae3d3cba24a97817b2a18c2421d462dbbce9f", 11 | "0xfa3bdc8709226da0da13a4d904c8b66f16c3c8ba", 12 | "0x6c365935ca8710200c7595f0a72eb6023a7706cd" 13 | ] 14 | } -------------------------------------------------------------------------------- /test/attestationClient/test-data/global-configs/global-150-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "startRoundId":150, 3 | "defaultSetAssignerAddresses": [ 4 | "0xead9c93b79ae7c1591b1fb5323bd777e86e150d4", 5 | "0xe5904695748fe4a84b40b3fc79de2277660bd1d3", 6 | "0x92561f28ec438ee9831d00d1d59fbdc981b762b2", 7 | "0x2ffd013aaa7b5a7da93336c2251075202b33fb2b", 8 | "0x9fc9c2dfba3b6cf204c37a5f690619772b926e39", 9 | "0xfbc51a9582d031f2ceaad3959256596c5d3a5468", 10 | "0x84fae3d3cba24a97817b2a18c2421d462dbbce9f", 11 | "0xfa3bdc8709226da0da13a4d904c8b66f16c3c8ba", 12 | "0x6c365935ca8710200c7595f0a72eb6023a7706cd" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_0-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "0", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0xd49743deccbccc5dc7baa8e69e5be03298da8688a15dd202e20f15d5e0e9a9fb", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1001, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true, 34 | "testSqlite3DBPath": "./db/attester_0.db" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_1-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "1", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x23c601ae397441f3ef6f1075dcb0031ff17fb079837beadaf3c84d96c6f3e569", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "2", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0xee9d129c1997549ee09c0757af5939b2483d80ad649a0eda68e8b0357ad11131", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_3-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "3", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x87630b2d1de0fbd5044eb6891b3d9d98c34c8d310c852f98550ba774480e47cc", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_4-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "4", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x275cc4a2bfd4f612625204a20a2280ab53a6da2d14860c47a9f5affe58ad86d4", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_5-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "5", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x7f307c41137d1ed409f0a7b028f6c7596f12734b1d289b58099b99d60a96efff", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_6-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "6", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x2a8aede924268f84156a00761de73998dac7bf703408754b776ff3f873bcec60", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_7-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "7", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x8b24fd94f1ce869d81a34b95351e7f97b2cd88a891d5c00abc33d0ec9501902e", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/attester_8-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "8", 3 | // epoch start time in unix time 4 | "firstEpochStartTime":1636070400, 5 | // epoch duration in seconds 6 | "roundDurationSec": 90, 7 | 8 | // Global configurations folder 9 | "globalConfigurationsFolder": "./test/attestationClient/test-data/global-configs/", 10 | 11 | // commit time in seconds, actual commit time is: epoch start + 2 * epoch duration + commit time (should be negative) 12 | "commitTimeSec": -3, 13 | 14 | // bit vote time in seconds relative to: epoch start + epoch duration + bit vote window + bitVoteTimeSec 15 | "bitVoteTimeSec": -3, 16 | 17 | // time to forcebely close bit voting: epoch start + epoch duration + bit vote window + forceCloseBitVotingSec 18 | "forceCloseBitVotingSec": 2, 19 | 20 | "web": { 21 | "accountPrivateKey": "0x28d1bfbbafe9d1d4f5a11c3c16ab6bf9084de48d99fbac4058bdfa3c80b29085", 22 | "rpcUrl": "http://127.0.0.1:8545", 23 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 24 | "refreshEventsMs": 1000, 25 | "bitVotingContractAddress": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", 26 | }, 27 | "attesterDatabase": { 28 | "host": "", 29 | "port": 1000, 30 | "database": "attester", 31 | "username": "", 32 | "password": "", 33 | "inMemory": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/spammer/btc-spammer-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // epoch start time in unix time 3 | "firstEpochStartTime": 1636070400, 4 | // epoch duration in seconds 5 | "roundDurationSec": 16, 6 | "numberOfConfirmations": 6, 7 | "web": { 8 | "accountPrivateKey": "0x28d1bfbbafe9d1d4f5a11c3c16ab6bf9084de48d99fbac4058bdfa3c80b2908a", 9 | "rpcUrl": "http://127.0.0.1:8545", 10 | "stateConnectorContractAddress": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", 11 | }, 12 | "indexerDatabase": { 13 | "port": 1000, 14 | "database": "indexer", 15 | "username": "", 16 | "password": "", 17 | "inMemory": true, 18 | "testSqlite3DBPath": "./db/btc-verifer.db" 19 | } 20 | } -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/verifier-server/btc-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9600, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "BTC", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction" 18 | ], 19 | "indexerDatabase": { 20 | "port": 3307, 21 | "database": "indexer", 22 | "username": "indexReader", 23 | "password": "password", 24 | "inMemory": true, 25 | "testSqlite3DBPath": "./db/btc-verifer.db" 26 | }, 27 | "chainConfiguration": { 28 | "name": "BTC", 29 | "mccCreate" : { 30 | "url": "https://bitcoin.flare.network/", 31 | "username": "flareadmin", 32 | "password": "password" 33 | }, 34 | "rateLimitOptions": { 35 | "maxRPS": 20, 36 | "timeoutMs": 15000, 37 | "retries": 3 38 | }, 39 | "numberOfConfirmations": 6, 40 | "syncReadAhead":10, 41 | "blockCollecting":"tips", 42 | "minimalStorageHistoryDays":2, 43 | "minimalStorageHistoryBlocks":100, 44 | } 45 | } -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/verifier-server/doge-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9602, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "DOGE", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "port": 3337, 18 | "database": "indexer", 19 | "username": "indexReader", 20 | "password": "password", 21 | "inMemory": true, 22 | "testSqlite3DBPath": "./db/doge-verifer.db" 23 | }, 24 | "chainConfiguration": { 25 | "name": "DOGE", 26 | "mccCreate": { 27 | "url": "https://doge.flare.network/", 28 | "username": "flareadmin", 29 | "password": "password" 30 | }, 31 | "rateLimitOptions": { 32 | "maxRPS": 20, 33 | "timeoutMs": 15000, 34 | "retries": 3 35 | }, 36 | "numberOfConfirmations": 6, 37 | "syncReadAhead": 10, 38 | "blockCollecting": "tips", 39 | "minimalStorageHistoryDays": 2, 40 | "minimalStorageHistoryBlocks": 100 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/verifier-server/xrp-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9601, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "XRP", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction" 18 | ], 19 | "indexerDatabase": { 20 | "port": 3307, 21 | "database": "", 22 | "username": "", 23 | "password": "", 24 | "inMemory": true, 25 | "testSqlite3DBPath": "./db/xrp-verifer.db" 26 | }, 27 | "chainConfiguration": { 28 | "name": "XRP", 29 | "mccCreate": { 30 | "url": "https://s.altnet.rippletest.net:51234/" 31 | }, 32 | "rateLimitOptions": { 33 | "maxRPS": 20, 34 | "timeoutMs": 30000, 35 | "retries": 10 36 | }, 37 | "numberOfConfirmations": 1, 38 | "syncReadAhead": 20, 39 | "blockCollecting": "raw", 40 | "minimalStorageHistoryDays": 2, 41 | "minimalStorageHistoryBlocks": 100, 42 | } 43 | } -------------------------------------------------------------------------------- /test/attestationClient/test-data/templates/webserver-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstEpochStartTime":1636070400, 3 | "roundDurationSec": 16, 4 | "serviceStatusFilePath": "../monitor-status.json", 5 | 6 | "port": 9610, 7 | 8 | "attesterDatabase": { 9 | "host": "", 10 | "port": 1001, 11 | "database": "attester", 12 | "username": "", 13 | "password": "", 14 | "inMemory": true, 15 | "testSqlite3DBPath": "./db/attester_0.db", 16 | "dropSchema": false, 17 | "synchronize": false 18 | } 19 | } -------------------------------------------------------------------------------- /test/attestationClient/utils/run-attester-spammer-btc.sh: -------------------------------------------------------------------------------- 1 | # Compile typescript 2 | # yarn tsc 3 | 4 | # Run DataProvider 5 | # node dist/src/spammer/attestation-spammer.js 6 | yarn ts-node src/spammer/attestation-spammer.ts \ 7 | -c BTC \ 8 | -d 5 \ 9 | -l BTC \ 10 | -t \ 11 | -f ../test/attestationClient/test-data 12 | -------------------------------------------------------------------------------- /test/attestationClient/utils/runTestWebServer.ts: -------------------------------------------------------------------------------- 1 | import { logException } from "../../../src/utils/logging/logger"; 2 | import { bootstrapAttestationWebServer } from "./attestation-client-test-utils"; 3 | 4 | 5 | process.env.NODE_ENV = "development" 6 | // Should be set from outside: 7 | // process.env.TEST_CREDENTIALS = "1"; 8 | // the correct: 9 | // process.env.SECURE_CONFIG_PATH 10 | 11 | bootstrapAttestationWebServer() 12 | .then(() => {}) 13 | .catch((error) => { 14 | logException(error, `runTestWebServer`); 15 | process.exit(1); 16 | }); 17 | -------------------------------------------------------------------------------- /test/caching/CachedMccClient.test-slow.ts: -------------------------------------------------------------------------------- 1 | import { ChainType } from "@flarenetwork/mcc"; 2 | import chai, { expect } from "chai"; 3 | import chaiaspromised from "chai-as-promised"; 4 | import sinon from "sinon"; 5 | import { CachedMccClient } from "../../src/caching/CachedMccClient"; 6 | import { initializeTestGlobalLogger } from "../../src/utils/logging/logger"; 7 | import { getTestFile } from "../test-utils/test-utils"; 8 | import { MockMccClient } from "./test-utils/MockMccClient"; 9 | chai.use(chaiaspromised); 10 | const CHAIN_ID = ChainType.XRP; 11 | 12 | describe(`Cached MCC Client test (${getTestFile(__filename)})`, function () { 13 | initializeTestGlobalLogger(); 14 | 15 | let mockMccClient: MockMccClient; 16 | beforeEach(async () => { 17 | mockMccClient = new MockMccClient(); 18 | sinon.stub(console, "log"); 19 | sinon.stub(console, "error"); 20 | }); 21 | 22 | afterEach(function () { 23 | sinon.restore(); 24 | }); 25 | 26 | it("Should terminate application after several retries", async function () { 27 | const cachedMccClient = new CachedMccClient(CHAIN_ID, { forcedClient: mockMccClient }); 28 | 29 | const stub1 = sinon.stub(process, "exit"); 30 | await cachedMccClient.getTransaction(""); 31 | expect(stub1.calledWith(2)).to.be.true; 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/caching/test-utils/btc-block-header.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "result": { 4 | "hash": "000000000000000000028ddeadc77fa5e5318412209e48c6ed836d832a91955c", 5 | "confirmations": 5, 6 | "height": 761551, 7 | "version": 536870912, 8 | "versionHex": "20000000", 9 | "merkleroot": "f985e75b3e775e29f84d6e0a13919959e2ce91a54439dd5b03e0fad49878e766", 10 | "time": 1667482401, 11 | "mediantime": 1667479760, 12 | "nonce": 2893687435, 13 | "bits": "1707a429", 14 | "difficulty": 36835682546787.98, 15 | "chainwork": "00000000000000000000000000000000000000003897342c09de4b38bbc2e970", 16 | "nTx": 2173, 17 | "previousblockhash": "000000000000000000021b4f21df2a788df1bfa5c0a3f97cc8ffabbe72bba390", 18 | "nextblockhash": "0000000000000000000509ad1cbda478c5c314c9eed25f68089d7fb0c805aa6f" 19 | }, 20 | "error": null, 21 | "id": "rpc" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/indexed-query-manager/test-data/templates/verifier-server/xrp-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9601, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "XRP", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction" 18 | ], 19 | "indexerDatabase": { 20 | "port": 3306, 21 | "database": "", 22 | "username": "", 23 | "password": "", 24 | "inMemory": true 25 | }, 26 | "chainConfiguration": { 27 | "name": "XRP", 28 | "mccCreate": { 29 | "url": "https://s.altnet.rippletest.net:51234/" 30 | }, 31 | "rateLimitOptions": { 32 | "maxRPS": 20, 33 | "timeoutMs": 30000, 34 | "retries": 10 35 | }, 36 | "numberOfConfirmations": 1, 37 | "syncReadAhead": 20, 38 | "blockCollecting": "raw", 39 | "minimalStorageHistoryDays": 2, 40 | "minimalStorageHistoryBlocks": 100, 41 | } 42 | } -------------------------------------------------------------------------------- /test/indexed-query-manager/test-data/xrp-account-set.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "Account": "r3TQUC9gNvbjXw3hFkLg5R8v8pGFsDsYsL", 4 | "Fee": "12", 5 | "LastLedgerSequence": 33157135, 6 | "Sequence": 15802588, 7 | "SigningPubKey": "022DE6752F92D552BCBB69AFDAF7948D1880E990DFB3D678AA1BE79FB41551256A", 8 | "TransactionType": "AccountSet", 9 | "TxnSignature": "3044022100E097598D656FF333A71496EE827F74B377D56BF57C4451BB3AB0D7B3E24A806C021F5C63645F4599C9B2486D1F5DE941448CED0C7FB4F775A7EA7768AC93417D74", 10 | "date": 722694982, 11 | "hash": "AB529CC5AF61850C0349DD4D6ECF26AA87C454221C0B5FCF00A9112CFD965F87", 12 | "meta": { 13 | "AffectedNodes": [ 14 | { 15 | "ModifiedNode": { 16 | "FinalFields": { 17 | "Account": "r3TQUC9gNvbjXw3hFkLg5R8v8pGFsDsYsL", 18 | "Balance": "999951615", 19 | "Flags": 0, 20 | "OwnerCount": 0, 21 | "Sequence": 15802589 22 | }, 23 | "LedgerEntryType": "AccountRoot", 24 | "LedgerIndex": "693D629F1EC3E1433DE1B80277CD20EBD45C60870598E61828DC8AF424EA4DAE", 25 | "PreviousFields": { 26 | "Balance": "999951627", 27 | "Sequence": 15802588 28 | }, 29 | "PreviousTxnID": "08D4B82DA7FDBC2E00112538B254EDE188F9A91A4CC36CB8B99C0F3F1AD292D6", 30 | "PreviousTxnLgrSeq": 33130409 31 | } 32 | } 33 | ], 34 | "TransactionIndex": 2, 35 | "TransactionResult": "tesSUCCESS" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/mockData/BTCBlockHeader.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "000000000000000000024e547ca314665a075dc7aeb365a7f9353cd3ba868c05", 3 | "confirmations": 10, 4 | "height": 765469, 5 | "version": 652500992, 6 | "versionHex": "26e46000", 7 | "merkleroot": "d2ac6f2818d10ee34205f96a673345608fe25c5b3da2cb286aa47556763c12ab", 8 | "time": 1669898290, 9 | "mediantime": 1669894829, 10 | "nonce": 3756085600, 11 | "bits": "17079e15", 12 | "difficulty": 36950494067222.41, 13 | "chainwork": "00000000000000000000000000000000000000003a97fe88f0ec006061c6f5ee", 14 | "nTx": 2448, 15 | "previousblockhash": "000000000000000000000c6e6ba4629ca4e397d4f2a2cb8aff4be613f6ccbacd", 16 | "nextblockhash": "000000000000000000078bcffb306f73289d84e36a4bc906687a9d32899afedc" 17 | } 18 | -------------------------------------------------------------------------------- /test/mockData/BTCBlockHeaderAlt.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "000000000000000000000c6e6ba4629ca4e397d4f2a2cb8aff4be613f6ccbacd", 3 | "confirmations": 11, 4 | "height": 765468, 5 | "version": 682745860, 6 | "versionHex": "28b1e004", 7 | "merkleroot": "ab1522908493c3c922d42a312ff42fd697645a8daa3b295bfecd8b8d1a1f501c", 8 | "time": 1669897489, 9 | "mediantime": 1669894683, 10 | "nonce": 2104451714, 11 | "bits": "17079e15", 12 | "difficulty": 36950494067222.41, 13 | "chainwork": "00000000000000000000000000000000000000003a97dced9a3def9be6e9a125", 14 | "nTx": 1673, 15 | "previousblockhash": "000000000000000000046366d8cb53098f70a0c286a26859c3b2c8724773a5a8", 16 | "nextblockhash": "000000000000000000024e547ca314665a075dc7aeb365a7f9353cd3ba868c05" 17 | } 18 | -------------------------------------------------------------------------------- /test/mockData/LTCBlockHeaderFake.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "8d1ba90d4443b7750c769861e2ed2a58480aec3ad1ea712e203af70525fa3d68", 3 | "confirmations": 3665, 4 | "height": 2402424, 5 | "version": 536870912, 6 | "versionHex": "20000000", 7 | "merkleroot": "93286e884c8d52e5536da46ac669c5208a104aca03e5d6fd31d19d3d37e8dd0f", 8 | "time": 1673421235, 9 | "mediantime": 1673419838, 10 | "nonce": 3593292362, 11 | "bits": "1a00cd8c", 12 | "difficulty": 20894999.06043329, 13 | "chainwork": "000000000000000000000000000000000000000000000a26dc523ea0c57e4019", 14 | "nTx": 59, 15 | "mweb_header": { 16 | "hash": "be1e5255d99e59f0127d67e8f9d519b0b73dc95a47f1c8995aff229e9458f431", 17 | "height": 2402424, 18 | "kernel_offset": "b21aca3e1936e0b4bd520c4b52cc2a936299d5004b1baaacc457a42a70e1f098", 19 | "stealth_offset": "0000000000000000000000000000000000000000000000000000000000000000", 20 | "num_kernels": 0, 21 | "num_txos": 15043, 22 | "kernel_root": "0000000000000000000000000000000000000000000000000000000000000000", 23 | "output_root": "0987d2a2924e744620f6036a94236ad5892344f1b6df9163036e37aba9ca8db0", 24 | "leaf_root": "9c1779f3403b5b795833c99ed42ebbe4b5dec9db3de3a5bad986d621a17f8ae3" 25 | }, 26 | "mweb_amount": 474999023680, 27 | "prev_mweb_amount": 474999023680, 28 | "previousblockhash": "4e5d57a1e8c3b9b1c2746c454107070200280e1557684d41fdfb8958c711bd9f", 29 | "nextblockhash": "dd3d3abdc8d240c35a91e84002dac88a0e51af4b192dab8a9f80570140348890" 30 | } 31 | -------------------------------------------------------------------------------- /test/mockData/XRPBlock.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "ledger": { 4 | "accepted": true, 5 | "account_hash": "E789F106A15A6C46D3AEF0EA1308123F5258F2BB1094C93723A1CF17A938FCF5", 6 | "close_flags": 0, 7 | "close_time": 721406520, 8 | "close_time_human": "2022-Nov-10 14:42:00.000000000 UTC", 9 | "close_time_resolution": 10, 10 | "closed": true, 11 | "hash": "67A8C07497CCE5AF2679840E712C9BEE03E4CE8FFCD29DA162655EDAC84EB211", 12 | "ledger_hash": "67A8C07497CCE5AF2679840E712C9BEE03E4CE8FFCD29DA162655EDAC84EB211", 13 | "ledger_index": "75660711", 14 | "parent_close_time": 721406511, 15 | "parent_hash": "5E976BD384AC6D70B5478F0E12DE3E2C4F3ADFCFD30C6CD0A15D726EA82235E7", 16 | "seqNum": "75660711", 17 | "totalCoins": "99989219487839748", 18 | "total_coins": "99989219487839748", 19 | "transaction_hash": "54FBA033204778EC1D295B722B4EE8BD350A191D1564EB289E9EEAE599901C62" 20 | }, 21 | "ledger_hash": "67A8C07497CCE5AF2679840E712C9BEE03E4CE8FFCD29DA162655EDAC84EB211", 22 | "ledger_index": 75660711, 23 | "status": "success", 24 | "validated": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/server/btc-verifier-server.test-dev.ts: -------------------------------------------------------------------------------- 1 | // This should always be on the top of the file, before imports 2 | import axios from "axios"; 3 | import chai from 'chai'; 4 | import chaiAsPromised from 'chai-as-promised'; 5 | import { EncodedRequest } from "../../src/servers/verifier-server/src/dtos/generic/generic.dto"; 6 | 7 | chai.use(chaiAsPromised); 8 | 9 | async function sendToVerifier(url: string, attestationRequest: EncodedRequest, apiKey: string) { 10 | const resp = await axios.post( 11 | url, 12 | attestationRequest, 13 | { 14 | headers: { 15 | "x-api-key": apiKey 16 | } 17 | } 18 | ); 19 | return resp.data; 20 | } 21 | 22 | 23 | describe(`Test request`, () => { 24 | 25 | 26 | before(async () => { 27 | 28 | }); 29 | 30 | 31 | it(`Should verify Payment attestation`, async function () { 32 | let port = 9600; 33 | const URL = `http://localhost:${port}/query` 34 | let request = "0x000200000000000000000000002f5e45a195844c4f53ebfcadd6d2b86eaea254143aa03c8a160e894916fc498c1b480b83452b91fa50281bc843f82dc7b1573e58ad19554fe200"; 35 | let attestationRequest = { 36 | abiEncodedRequest: request, 37 | } as EncodedRequest; 38 | 39 | let resp = await sendToVerifier(URL, attestationRequest, "123456"); 40 | console.log(resp) 41 | 42 | }); 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /test/server/dev-test-data/db/attester_0.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/test/server/dev-test-data/db/attester_0.db -------------------------------------------------------------------------------- /test/server/dev-test-data/db/attester_0.db-shm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/test/server/dev-test-data/db/attester_0.db-shm -------------------------------------------------------------------------------- /test/server/dev-test-data/db/attester_0.db-wal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/test/server/dev-test-data/db/attester_0.db-wal -------------------------------------------------------------------------------- /test/server/dev-test-data/db/xrp-verifer.db-shm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/test/server/dev-test-data/db/xrp-verifer.db-shm -------------------------------------------------------------------------------- /test/server/dev-test-data/db/xrp-verifer.db-wal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/test/server/dev-test-data/db/xrp-verifer.db-wal -------------------------------------------------------------------------------- /test/server/dev-test-data/templates/verifier-server/btc-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9600, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "BTC", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction" 18 | ], 19 | "indexerDatabase": { 20 | "port": 3307, 21 | "database": "indexer", 22 | "username": "indexReader", 23 | "password": "password", 24 | "inMemory": true, 25 | "testSqlite3DBPath": "./test/server/dev-test-data/db/btc-verifer.db", 26 | "dropSchema": false, 27 | "synchronize": false 28 | }, 29 | "chainConfiguration": { 30 | "name": "BTC", 31 | "mccCreate" : { 32 | "url": "https://bitcoin.flare.network/", 33 | "username": "flareadmin", 34 | "password": "password" 35 | }, 36 | "rateLimitOptions": { 37 | "maxRPS": 20, 38 | "timeoutMs": 15000, 39 | "retries": 3 40 | }, 41 | "numberOfConfirmations": 6, 42 | "syncReadAhead":10, 43 | "blockCollecting":"tips", 44 | "minimalStorageHistoryDays":2, 45 | "minimalStorageHistoryBlocks":100 46 | } 47 | } -------------------------------------------------------------------------------- /test/server/dev-test-data/templates/verifier-server/doge-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9600, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "DOGE", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "name": "db", 18 | "type": "postgres", 19 | "host": "127.0.0.1", 20 | "port": 8080, 21 | "username": "user", 22 | "password": "pass", 23 | "database": "db" 24 | }, 25 | "chainConfiguration": { 26 | "name": "BTC", 27 | "mccCreate": { 28 | "url": "https://bitcoin.flare.network/", 29 | "username": "flareadmin", 30 | "password": "password" 31 | }, 32 | "rateLimitOptions": { 33 | "maxRPS": 20, 34 | "timeoutMs": 15000, 35 | "retries": 3 36 | }, 37 | "numberOfConfirmations": 6, 38 | "syncReadAhead": 10, 39 | "blockCollecting": "tips", 40 | "minimalStorageHistoryDays": 2, 41 | "minimalStorageHistoryBlocks": 100 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/server/dev-test-data/templates/verifier-server/xrp-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9601, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "XRP", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction" 18 | ], 19 | "indexerDatabase": { 20 | "port": 3307, 21 | "database": "", 22 | "username": "", 23 | "password": "", 24 | "inMemory": true, 25 | "testSqlite3DBPath": "./test/server/dev-test-data/db/xrp-verifer.db", 26 | "dropSchema": false, 27 | "synchronize": false 28 | }, 29 | "chainConfiguration": { 30 | "name": "XRP", 31 | "mccCreate": { 32 | "url": "https://s.altnet.rippletest.net:51234/" 33 | }, 34 | "rateLimitOptions": { 35 | "maxRPS": 20, 36 | "timeoutMs": 30000, 37 | "retries": 10 38 | }, 39 | "numberOfConfirmations": 1, 40 | "syncReadAhead": 20, 41 | "blockCollecting": "raw", 42 | "minimalStorageHistoryDays": 2, 43 | "minimalStorageHistoryBlocks": 100, 44 | } 45 | } -------------------------------------------------------------------------------- /test/server/dev-test-data/templates/webserver-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstEpochStartTime":1636070400, 3 | "roundDurationSec": 8, 4 | "serviceStatusFilePath": "../monitor-status.json", 5 | 6 | "port": 9610, 7 | 8 | "attesterDatabase": { 9 | "host": "", 10 | "port": 1001, 11 | "database": "attester", 12 | "username": "", 13 | "password": "", 14 | "inMemory": true, 15 | "testSqlite3DBPath": "./test/server/dev-test-data/db/attester_0.db", 16 | "dropSchema": false, 17 | "synchronize": false 18 | } 19 | } -------------------------------------------------------------------------------- /test/server/test-data/db/attester_0.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flare-foundation/attestation-client/af88df2adf6d2307bf52f05258ae8523c8d93878/test/server/test-data/db/attester_0.db -------------------------------------------------------------------------------- /test/server/test-data/templates/verifier-server/btc-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9601, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "BTC", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "port": 3306, 18 | "database": "indexer", 19 | "username": "indexReader", 20 | "password": "password", 21 | "inMemory": true 22 | }, 23 | "chainConfiguration": { 24 | "name": "BTC", 25 | "mccCreate": { 26 | "url": "https://bitcoin.flare.network/", 27 | "username": "flareadmin", 28 | "password": "password" 29 | }, 30 | "rateLimitOptions": { 31 | "maxRPS": 20, 32 | "timeoutMs": 15000, 33 | "retries": 3 34 | }, 35 | "numberOfConfirmations": 6, 36 | "syncReadAhead": 10, 37 | "blockCollecting": "tips", 38 | "minimalStorageHistoryDays": 2, 39 | "minimalStorageHistoryBlocks": 100 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/server/test-data/templates/verifier-server/doge-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 8080, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "DOGE", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "port": 5432, 18 | "database": "db", 19 | "username": "db", 20 | "password": "secret" 21 | }, 22 | "chainConfiguration": { 23 | "name": "DOGE", 24 | "mccCreate": { 25 | "url": "https://doge.flare.network/", 26 | "username": "flareadmin", 27 | "password": "password" 28 | }, 29 | "rateLimitOptions": { 30 | "maxRPS": 20, 31 | "timeoutMs": 15000, 32 | "retries": 3 33 | }, 34 | "numberOfConfirmations": 6, 35 | "syncReadAhead": 10, 36 | "blockCollecting": "tips", 37 | "minimalStorageHistoryDays": 2, 38 | "minimalStorageHistoryBlocks": 100 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/server/test-data/templates/verifier-server/xrp-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9600, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "XRP", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "port": 3306, 18 | "database": "", 19 | "username": "", 20 | "password": "", 21 | "inMemory": true 22 | }, 23 | "chainConfiguration": { 24 | "name": "XRP", 25 | "mccCreate": { 26 | "url": "https://s.altnet.rippletest.net:51234/" 27 | }, 28 | "rateLimitOptions": { 29 | "maxRPS": 20, 30 | "timeoutMs": 30000, 31 | "retries": 10 32 | }, 33 | "numberOfConfirmations": 1, 34 | "syncReadAhead": 20, 35 | "blockCollecting": "raw", 36 | "minimalStorageHistoryDays": 2, 37 | "minimalStorageHistoryBlocks": 100 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/server/test-data/templates/webserver-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstEpochStartTime": 1636070400, 3 | "roundDurationSec": 8, 4 | "serviceStatusFilePath": "../monitor-status.json", 5 | 6 | "port": 9610, 7 | 8 | "attesterDatabase": { 9 | "host": "", 10 | "port": 1001, 11 | "database": "attester", 12 | "username": "", 13 | "password": "", 14 | "inMemory": true, 15 | "testSqlite3DBPath": "./test/server/test-data/db/attester_0.db", 16 | "dropSchema": false, 17 | "synchronize": false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/server/test-data/test-doge-db-docker.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | database: 5 | image: "postgres" 6 | restart: always 7 | container_name: test-db-doge 8 | 9 | ports: 10 | - 5432:5432 11 | 12 | environment: 13 | POSTGRES_USER: db 14 | POSTGRES_PASSWORD: secret 15 | POSTGRES_DB: db 16 | volumes: 17 | - ./db/dbdump-4958001-4960500:/entrypoint/dump.sql 18 | -------------------------------------------------------------------------------- /test/server/utils/server-test-utils.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { EncodedRequest } from "../../../src/servers/verifier-server/src/dtos/generic/generic.dto"; 3 | import { VerifierConfigurationService } from "../../../src/servers/verifier-server/src/services/verifier-configuration.service"; 4 | 5 | export async function sendToVerifier( 6 | attestationType: string, 7 | sourceId: string, 8 | configurationService: VerifierConfigurationService, 9 | attestationRequest: EncodedRequest, 10 | apiKey?: string 11 | ) { 12 | const resp = await axios.post(`http://localhost:${configurationService.config.port}/${attestationType}`, attestationRequest, { 13 | headers: { 14 | "x-api-key": apiKey, 15 | }, 16 | }); 17 | return resp.data; 18 | } 19 | -------------------------------------------------------------------------------- /test/test-utils/test-utils.ts: -------------------------------------------------------------------------------- 1 | import { traceManager } from "@flarenetwork/mcc"; 2 | import { getRetryFailureCallback, setRetryFailureCallback } from "../../src/utils/helpers/promiseTimeout"; 3 | import { getGlobalLogger } from "../../src/utils/logging/logger"; 4 | 5 | export const TERMINATION_TOKEN = "Mock Application terminated"; 6 | 7 | export async function testWithoutLoggingTracingAndApplicationTermination(func: any, noTracing = true, noLogging = true, noTermination = true) { 8 | const oldTracing = traceManager.displayStateOnException; 9 | const oldLevel = getGlobalLogger().level; 10 | const oldOnRetryFailure = getRetryFailureCallback(); 11 | if (noLogging) { 12 | traceManager.displayStateOnException = false; 13 | } 14 | if (noTermination) { 15 | setRetryFailureCallback((label: string) => { throw new Error(TERMINATION_TOKEN) }); 16 | } 17 | if (noLogging) { 18 | getGlobalLogger().level = "alert"; 19 | } 20 | 21 | await func(); 22 | 23 | // recover 24 | traceManager.displayStateOnException = oldTracing; 25 | getGlobalLogger().level = oldLevel; 26 | setRetryFailureCallback(oldOnRetryFailure); 27 | } 28 | 29 | /** 30 | * Returns truncated file path. 31 | * @param file module filename 32 | * @returns file path from `test/` on, separated by `'/'` 33 | */ 34 | export function getTestFile(myFile: string) { 35 | return myFile.slice(myFile.replace(/\\/g, '/').indexOf("test/")); 36 | }; 37 | -------------------------------------------------------------------------------- /test/types/@openzeppelin/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "@openzeppelin" {} 2 | -------------------------------------------------------------------------------- /test/utils/Queue.test.ts: -------------------------------------------------------------------------------- 1 | // yarn test test/utils/Queue.test.ts 2 | 3 | import { assert, expect } from "chai"; 4 | import { Queue } from "../../src/utils/data-structures/Queue"; 5 | import { getTestFile } from "../test-utils/test-utils"; 6 | 7 | describe(`Queue ${getTestFile(__filename)})`, () => { 8 | let queue = new Queue(); 9 | for (let i = 0; i < 15; i++) { 10 | queue.push(i); 11 | } 12 | 13 | it("Should prepend", () => { 14 | const preSize = queue.size; 15 | queue.prepend(91); 16 | assert(queue.size === preSize + 1); 17 | }); 18 | 19 | it("Should return first element in the queue", () => { 20 | assert(queue.shift() === 91); 21 | assert(queue.size === 15); 22 | }); 23 | 24 | it("Should push", () => { 25 | const preSize = queue.size; 26 | queue.push(91); 27 | assert(queue.size === preSize + 1); 28 | }); 29 | 30 | it("Should destroy queue", () => { 31 | queue.destroy(); 32 | assert(queue.size === 0); 33 | }); 34 | 35 | it("Should not get the first from an empty queue", () => { 36 | expect(() => { 37 | queue.first; 38 | }).to.throw("Empty queue"); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/utils/databaseService.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { DatabaseConnectOptions } from "../../src/utils/database/DatabaseConnectOptions"; 3 | import { DatabaseService } from "../../src/utils/database/DatabaseService"; 4 | import { getGlobalLogger, initializeTestGlobalLogger } from "../../src/utils/logging/logger"; 5 | import { getTestFile } from "../test-utils/test-utils"; 6 | 7 | describe(`DatabaseService tests (${getTestFile(__filename)})`, function () { 8 | const databaseConnectOptions = new DatabaseConnectOptions(); 9 | 10 | let dataService: DatabaseService; 11 | before(async function () { 12 | initializeTestGlobalLogger(); 13 | dataService = new DatabaseService(getGlobalLogger(), databaseConnectOptions, "", "", true); 14 | await dataService.connect(); 15 | }); 16 | 17 | it("Should be initialized", function () { 18 | expect(dataService.dataSource.isInitialized).to.be.true; 19 | }); 20 | 21 | it("Should get manager", function () { 22 | const mng = dataService.manager; 23 | expect(!mng).to.be.false; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/utils/internetTime.test.ts: -------------------------------------------------------------------------------- 1 | // yarn test test/utils/internetTime.test.ts 2 | 3 | import { assert } from "chai"; 4 | import { getTimeSec, getTimeMs } from "../../src/utils/helpers/internetTime"; 5 | import { getTestFile } from "../test-utils/test-utils"; 6 | 7 | describe(`Internet time (${getTestFile(__filename)})`, () => { 8 | it("Should get time in milliseconds", () => { 9 | const timeMil = getTimeMs(); 10 | assert(timeMil > 1666622201459); 11 | }); 12 | 13 | it("Should get time in seconds", () => { 14 | const timeSec = getTimeSec(); 15 | assert(timeSec > 1666622201); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/utils/test-data/config/keys1-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1" : 1, 3 | "key2" : 2, 4 | } -------------------------------------------------------------------------------- /test/utils/test-data/config/keys2-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "key3" : 3, 3 | "key4" : 4, 4 | } -------------------------------------------------------------------------------- /test/utils/test-data/config/templates/env_test-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "test" : "$(env:ENV_TEST)", 3 | } -------------------------------------------------------------------------------- /test/utils/test-data/config/templates/template1-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1" : $(key1), 3 | "key2" : $(key2), 4 | "key3" : $(key3), 5 | "key4" : $(key4), 6 | } -------------------------------------------------------------------------------- /test/utils/test-data/config/templates/template1-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1" : $(key1), 3 | "key2" : $(key2), 4 | "key3" : $(key3), 5 | "key4" : $(key4), 6 | } -------------------------------------------------------------------------------- /test/utils/test-data/credentials.key: -------------------------------------------------------------------------------- 1 | test:address -------------------------------------------------------------------------------- /test/utils/test-data/json_test_eol_comment.json: -------------------------------------------------------------------------------- 1 | // EOL comment 1 2 | { 3 | "test":1 // EOL comment 2 4 | } -------------------------------------------------------------------------------- /test/verification/attestationTypeHelpers.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { randomListElement } from "../../src/verification/attestation-types/attestation-types-helpers"; 3 | import { getTestFile } from "../test-utils/test-utils"; 4 | 5 | describe(`Attestation Helpers Tests (${getTestFile(__filename)})`, function () { 6 | describe(`randomListElement`, function () { 7 | it("empty array", function () { 8 | const arr: number[] = [] 9 | const randomElem = randomListElement(arr); 10 | 11 | expect(randomElem).to.eq(undefined); 12 | expect(typeof randomElem).to.eq('undefined') 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/verification/test-data/templates/verifier-server/btc-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9600, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "BTC", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "port": 3337, 18 | "database": "indexer", 19 | "username": "indexReader", 20 | "password": "password", 21 | "inMemory": true 22 | }, 23 | "chainConfiguration": { 24 | "name": "BTC", 25 | "mccCreate": { 26 | "url": "https://bitcoin.flare.network/", 27 | "username": "flareadmin", 28 | "password": "password" 29 | }, 30 | "rateLimitOptions": { 31 | "maxRPS": 20, 32 | "timeoutMs": 15000, 33 | "retries": 3 34 | }, 35 | "numberOfConfirmations": 6, 36 | "syncReadAhead": 10, 37 | "blockCollecting": "tips", 38 | "minimalStorageHistoryDays": 2, 39 | "minimalStorageHistoryBlocks": 100 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/verification/test-data/templates/verifier-server/doge-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9602, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "DOGE", 15 | "attestationTypes": ["Payment", "BalanceDecreasingTransaction"], 16 | "indexerDatabase": { 17 | "port": 3337, 18 | "database": "indexer", 19 | "username": "indexReader", 20 | "password": "password", 21 | "inMemory": true 22 | }, 23 | "chainConfiguration": { 24 | "name": "DOGE", 25 | "mccCreate": { 26 | "url": "https://doge.flare.network/", 27 | "username": "flareadmin", 28 | "password": "password" 29 | }, 30 | "rateLimitOptions": { 31 | "maxRPS": 20, 32 | "timeoutMs": 15000, 33 | "retries": 3 34 | }, 35 | "numberOfConfirmations": 6, 36 | "syncReadAhead": 10, 37 | "blockCollecting": "tips", 38 | "minimalStorageHistoryDays": 2, 39 | "minimalStorageHistoryBlocks": 100 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/verification/test-data/templates/verifier-server/xrp-verifier-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiKeys": [ 3 | { 4 | "name": "test1", 5 | "apiKey": "123456" 6 | }, 7 | { 8 | "name": "test2", 9 | "apiKey": "7890" 10 | } 11 | ], 12 | "port": 9601, 13 | "checkAliveIntervalMs": 5000, 14 | "sourceId": "XRP", 15 | "attestationTypes": [ 16 | "Payment", 17 | "BalanceDecreasingTransaction" 18 | ], 19 | "indexerDatabase": { 20 | "port": 3306, 21 | "database": "", 22 | "username": "", 23 | "password": "", 24 | "inMemory": true 25 | }, 26 | "chainConfiguration": { 27 | "name": "XRP", 28 | "mccCreate": { 29 | "url": "https://s.altnet.rippletest.net:51234/" 30 | }, 31 | "rateLimitOptions": { 32 | "maxRPS": 20, 33 | "timeoutMs": 30000, 34 | "retries": 10 35 | }, 36 | "numberOfConfirmations": 1, 37 | "syncReadAhead": 20, 38 | "blockCollecting": "raw", 39 | "minimalStorageHistoryDays": 2, 40 | "minimalStorageHistoryBlocks": 100, 41 | } 42 | } -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "outDir": "dist", 7 | "strictNullChecks": false, 8 | "noFallthroughCasesInSwitch": false, 9 | "moduleResolution": "node", 10 | "baseUrl": ".", 11 | "paths": { 12 | "*": ["node_modules/*"], 13 | "@atc/common": ["src/servers/common/src"], 14 | "@atc/common/*": ["src/servers/common/src/*"] 15 | }, 16 | "esModuleInterop": true, 17 | "experimentalDecorators": true, 18 | "emitDecoratorMetadata": true, 19 | "skipLibCheck": true, 20 | "forceConsistentCasingInFileNames": true, 21 | "resolveJsonModule": true, 22 | "lib": ["ES2021.String"] 23 | }, 24 | "include": ["src/**/*", "./typechain-web3-v1", "./typechain-web3-v1-new", "./typechain-truffle", "./test"], 25 | "files": ["./hardhat.config.ts", "src/entity-external/DogeExternalEntities.ts"] 26 | } 27 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "trailing-comma": [ 9 | false 10 | ], 11 | "no-console": false, 12 | "no-bitwise": false 13 | }, 14 | "rulesDirectory": [] 15 | } -------------------------------------------------------------------------------- /typedoc.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "excludeExternals": true, 3 | "entryPoints": ["./src"], 4 | "categorizeByGroup": true, 5 | "categoryOrder": ["BaseMethod", "AdvancedMethod", "Indexer", "Verifiers", "*"], 6 | "mergeModulesMergeMode": "project", 7 | "entryPointStrategy": "expand", 8 | "out": "genDocs", 9 | "pluginPages": { 10 | "output": "", 11 | "pages": [ 12 | { "title": "Documentation Home", "source": "./docs/README.md" }, 13 | { "title": "Using connected Testnets", "source": "./docs/testnets/README.md" } 14 | ] 15 | } 16 | } --------------------------------------------------------------------------------