diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 32d9cc8d05..5c5e1b1db3 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -29,6 +29,7 @@ module.exports = { { files: ['*-mock.js', '*.test.js'], rules: { + 'no-empty-function': 'off', 'no-unused-vars': 'off', }, }, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f8ecbe5a4c..3dad05a1ab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @branarakic @djordjekovac @kotlarmilos @NZT48 @zeroxbt +* @branarakic @djordjekovac @NZT48 @zeroxbt @u-hubar diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 64356fb2f4..f7dee6cf44 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -2,8 +2,7 @@ name: checks on: pull_request: - branches: - - v6/develop + types: [opened, reopened, synchronize] env: REPOSITORY_PASSWORD: password diff --git a/README.md b/README.md index 319b9d61cc..c4fd787499 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,285 @@ -# OriginTrail Decentralized Knowledge Graph network node - OT-Node v6 + +___ -OriginTrail technology is a set of tools and protocols evolving as the semantic layer for Web3, built on the OriginTrail Decentralized Knowledge Graph (DKG). Its function is to empower developers and system integrators utilizing decentralized knowledge exchange supported by emerging standards and DLT networks. +
+
+ + OriginTrail Node Banner + -Version 6 is the latest implementation of OriginTrail Decentralized Knowledge Graph. OriginTrail is currently in the launch procedure. +

OT-Node

-The DKG v6 introduces various improvements to the existing OriginTrail DKG. Among others, it will introduce: - - the Universal Asset Locator (UAL), akin to URLs in Web2 - - improved discoverability, performance and semantic powers with the expanding support for semantic technologies such as RDF, OWL, SPARQL, Triple Pattern Fragments, SHACL and others - - numerous performance updates to the protocol & network implementation +

+
+ OriginTrail Docs + Β· + Report Bug + Β· + Request Feature +

+
-To learn more about OriginTrail v6, check out this blogpost. +
-## Contribution +
+ + Table of Contents + +
    +
  1. + πŸ“š About The Project + +
  2. +
  3. + πŸš€ Getting Started + +
  4. +
  5. πŸ“„ License
  6. +
  7. 🀝 Contributing
  8. +
  9. πŸ“° Social Media
  10. +
+
-OriginTrail software is open source (Apache 2 licence) and open for contributions by anyone. We encourage the developer community to submit [issues](https://github.com/OriginTrail/ot-node/issues) and [pull requests](https://github.com/OriginTrail/ot-node/pulls) for DKG v6 on this repo. Please have the issue/PR name formatted like this for easy navigation: ``` [v6] Issue name goes here ``` +___ -For a live discussion you are welcome to join the OriginTrail tech community in our [Discord](https://discordapp.com/invite/FCgYk2S)! +
-## Launch procedure -The OriginTrail DKG v6 launch is performed in 3 stages: - - Stage 1 which introduces the new network and data layer. The goal of Stage1 is to verify smooth operation of the v6 network and data layer in a public network environment. - - Stage 2 which introduces the incentivisation layer (smart contracts and TRAC token). Stage 2 immediately kicks in once stage 1 KPIs are stable, which will introduce the incentivisation layer, implemented through smart contracts, opening the doors for token delegation, staking and improving several existing mechanisms - - Stage 3 will be focused on performing the migration from v5 to the v6 mainnet. +## πŸ“š About The Project -Throughout the stages the OriginTrail community is invited to participate by actively utilizing the v6 network. Each node will be capable of collecting granular network KPI and telemetry data and publishing it to the DKG itself, further utilized by the core developers to improve the DKG implementation and proceed through the launch stages. For that purpose, there will be a designated reward pool that node runners will be able to collect by submitting relevant network utilization data. All node runners will be motivated to test and utilize their nodes in various creative ways, in order to generate as much quality DKG utilization data to be able to collect rewards. The collected data will include performance metrics, collected error information from bugs occurrences and other. More details on the reward pool distribution among all node runners will be available shortly. +
+ -## Node setup instructions +### **What is the Decentralized Knowledge Graph?** + -Setup instructions are available in the [official documentation](https://docs.origintrail.io/). +
+
+ Knowledge Asset +
+OriginTrail Decentralized Knowledge Graph (DKG), hosted on the OriginTrail Decentralized Network (ODN) as trusted knowledge infrastructure, is shared global Knowledge Graph of Knowledge Assets. Running on the basis of the permissionless multi-chain OriginTrail protocol, it combines blockchains and knowledge graph technology to enable trusted AI applications based on key W3C standards. +
+ +
+ + +### **The OriginTrail DKG Architecture** + + +
+ +The OriginTrail tech stack is a three layer structure, consisting of the multi-chain consensus layer (OriginTrail layer 1, running on multiple blockchains), the Decentralized Knowledge Graph layer (OriginTrail Layer 2, hosted on the ODN) and Trusted Knowledge applications in the application layer. + +
+ DKG Architecture +
+ +Further, the architecture differentiates between **the public, replicated knowledge graph** shared by all network nodes according to the protocol, and **private Knowledge graphs** hosted separately by each of the OriginTrail nodes. + +**Anyone can run an OriginTrail node and become part of the ODN, contributing to the network capacity and hosting the OriginTrail DKG. The OriginTrail node is the ultimate data service for data and knowledge intensive Web3 applications and is used as the key backbone for trusted AI applications (see https://chatdkg.ai)** +
+ +
+ + +### **What is a Knowledge Asset?** + + +
+ +
+ Knowledge Asset +
+ +**Knowledge Asset is the new, AI‑ready resource for the Internet** + +Knowledge Assets are verifiable containers of structured knowledge that live on the OriginTrail DKG and provide: +- **Discoverability - UAL is the new URL**. Uniform Asset Locators (UALs, based on the W3C Decentralized Identifiers) are a new Web3 knowledge identifier (extensions of the Uniform Resource Locators - URLs) which identify a specific piece of knowledge and make it easy to find and connect with other Knowledge Assets. +- **Ownership - NFTs enable ownership**. Each Knowledge Asset contains an NFT token that enables ownership, knowledge asset administration and market mechanisms. +- **Verifiability - On-chain information origin and verifiable trail**. The blockchain tech increases trust, security, transparency, and the traceability of information. + +By their nature, Knowledge Assets are semantic resources (following the W3C Semantic Web set of standards), and through their symbolic representations inherently AI ready. See more at https://chatdkg.ai +
+ +**Discover Knowledge Assets with the DKG Explorer:** +
+ + + + + + + +
+ + Knowledge Assets Graph 1 + +
Supply Chains +
+ + Knowledge Assets Graph 2 + +
Construction +
+ + Knowledge Assets Graph 3 + +
Life sciences and healthcare +
+ + Knowledge Assets Graph 3 + +
Metaverse +
+
+ + +
+ +

(back to top)

+
+ +## πŸš€ Getting Started + +___ + +### Prerequisites + +
+ +- **NodeJS** >= 16.0.0 +- **npm** >= 8.0.0 + +___ +
+ +### Local Network Setup + +
+ +First, clone the repo: +```bash +git clone https://github.com/OriginTrail/ot-node.git +cd ot-node +``` + +Install dependencies using `npm`: +```bash +npm install +``` + +Run the Triple Store. + +To use default Triple Store (`blazegraph`), download the exec file and run it with the following command in the separate process: +```bash +java -server -Xmx4g -jar blazegraph.jar +``` + +Then, depending on the OS, use one of the scripts in order to run the local network with provided number of nodes (minimal amount of nodes should be 12): + +**MacOS** +```bash +bash ./tools/local-network-setup/setup-macos-environment.sh --nodes=12 +``` + +___ +
+ +### DKG Node Setup + +
+ +In order to run a DKG node on the **Testnet** or **Mainnet**, please read the official documentation: https://docs.origintrail.io/decentralized-knowledge-graph-layer-2/node-setup-instructions/setup-instructions-dockerless + +___ +
+ +### Build on DKG + +
+ +The OriginTrail SDKs are client libraries for your applications, used to interact and connect with the OriginTrail Decentralized Knowledge Graph. +From an architectural standpoint, the SDK libraries are application interfaces into the DKG, enabling you to create and manage Knowledge Assets through your apps, as well as perform network queries (such as search, or SPARQL queries), as illustrated below. + +
+ SDK +
+ +The OriginTrail SDK libraries are being built in various languages by the team and the community, as listed below: +- dkg.js - JavaScript SDK implementation + - [Github repository](https://github.com/OriginTrail/dkg.js) + - [Documentation](https://docs.origintrail.io/decentralized-knowledge-graph-layer-2/dkg-sdk/dkg-v6-js-client) +- dkg.py - Python SDK implementation + - [Github repository](https://github.com/OriginTrail/dkg.py) + - [Documentation](https://docs.origintrail.io/decentralized-knowledge-graph-layer-2/dkg-sdk/dkg-v6-py-client) +___ + +
+

(back to top)

+ +## πŸ“„ License + +Distributed under the Apache-2.0 License. See `LICENSE` file for more information. + +
+

(back to top)

+ +## 🀝 Contributing + +Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". +Don't forget to give the project a star! Thanks again! + +1. Fork the Project +2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) +3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the Branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +
+

(back to top)

+ +## πŸ“° Social Media + +
+ +
+ + Medium Badge + + + Telegram Badge + + + X Badge + + + YouTube Badge + + + LinkedIn Badge + + + Discord Badge + + + Reddit Badge + + + Coinmarketcap Badge + +
+ +___ diff --git a/config/config.json b/config/config.json index 8f3679f4c2..e16f1e509d 100644 --- a/config/config.json +++ b/config/config.json @@ -131,7 +131,10 @@ "config": { "networkId": "otp::testnet", "hubContractAddress": "0x707233a55bD035C6Bc732196CA4dbffa63CbA169", - "rpcEndpoints": ["wss://lofar.origin-trail.network"], + "rpcEndpoints": [ + "https://lofar-tm-rpc.origin-trail.network", + "https://lofar.origintrail.network/" + ], "initialStakeAmount": 50000, "initialAskAmount": 2 } @@ -166,17 +169,25 @@ } } } + }, + "telemetry": { + "enabled": true, + "implementation": { + "ot-telemetry": { + "enabled": true, + "package": "./telemetry/implementation/ot-telemetry.js", + "config": { + "sendTelemetryData": false, + "signalingServerUrl": "null" + } + } + } } }, "maximumAssertionSizeInKb": 2500, "commandExecutorVerboseLoggingEnabled": false, "appDataPath": "data", "logLevel": "info", - "telemetry": { - "enabled": true, - "sendTelemetryData": false, - "signalingServerUrl": "null" - }, "auth": { "ipBasedAuthEnabled": true, "tokenBasedAuthEnabled": false, @@ -301,17 +312,25 @@ "config": {} } } + }, + "telemetry": { + "enabled": true, + "implementation": { + "ot-telemetry": { + "enabled": true, + "package": "./telemetry/implementation/ot-telemetry.js", + "config": { + "sendTelemetryData": false, + "signalingServerUrl": "null" + } + } + } } }, "maximumAssertionSizeInKb": 2500, "commandExecutorVerboseLoggingEnabled": false, "appDataPath": "data", "logLevel": "trace", - "telemetry": { - "enabled": true, - "sendTelemetryData": false, - "signalingServerUrl": "null" - }, "auth": { "ipBasedAuthEnabled": true, "tokenBasedAuthEnabled": false, @@ -413,8 +432,7 @@ "hubContractAddress": "0xBbfF7Ea6b2Addc1f38A0798329e12C08f03750A6", "rpcEndpoints": [ "https://lofar-testnet.origin-trail.network", - "https://lofar-testnet.origintrail.network", - "wss://parachain-testnet-rpc.origin-trail.network" + "https://lofar-testnet.origintrail.network" ] } } @@ -449,17 +467,25 @@ "config": {} } } + }, + "telemetry": { + "enabled": true, + "implementation": { + "ot-telemetry": { + "enabled": true, + "package": "./telemetry/implementation/ot-telemetry.js", + "config": { + "sendTelemetryData": true, + "signalingServerUrl": "https://testnet-signaling.origin-trail.network/signal" + } + } + } } }, "maximumAssertionSizeInKb": 2500, "commandExecutorVerboseLoggingEnabled": false, "appDataPath": "data", "logLevel": "trace", - "telemetry": { - "enabled": true, - "sendTelemetryData": true, - "signalingServerUrl": "https://testnet-signaling.origin-trail.network/signal" - }, "auth": { "ipBasedAuthEnabled": true, "tokenBasedAuthEnabled": false, @@ -563,7 +589,7 @@ "rpcEndpoints": [ "https://astrosat-parachain-rpc.origin-trail.network", "https://astrosat.origintrail.network/", - "wss://parachain-rpc.origin-trail.network" + "https://astrosat-2.origintrail.network/" ] } } @@ -598,17 +624,25 @@ "config": {} } } + }, + "telemetry": { + "enabled": true, + "implementation": { + "ot-telemetry": { + "enabled": true, + "package": "./telemetry/implementation/ot-telemetry.js", + "config": { + "sendTelemetryData": true, + "signalingServerUrl": "https://mainnet-signaling.origin-trail.network/signal" + } + } + } } }, "maximumAssertionSizeInKb": 2500, "commandExecutorVerboseLoggingEnabled": false, "appDataPath": "data", "logLevel": "trace", - "telemetry": { - "enabled": true, - "sendTelemetryData": true, - "signalingServerUrl": "https://mainnet-signaling.origin-trail.network/signal" - }, "auth": { "ipBasedAuthEnabled": true, "tokenBasedAuthEnabled": false, diff --git a/docs/openapi/DKGv6.yaml b/docs/openapi/DKGv6.yaml new file mode 100644 index 0000000000..5964ab8356 --- /dev/null +++ b/docs/openapi/DKGv6.yaml @@ -0,0 +1,1369 @@ +openapi: 3.0.3 +info: + title: DKGv6 + description: DKG v6 API Collection. + version: 1.0.0 + contact: {} +servers: + - url: localhost +paths: + /info: + get: + tags: + - old + summary: Node Info + description: Get the node information. + operationId: nodeInfo + responses: + '200': + description: Node Info + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '20' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 12:43:07 GMT + ETag: + schema: + type: string + example: W/"14-Rq/28W5aGKCGXmXfM1+eW1LAbb4" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + version: + type: string + example: 6.0.13 + examples: + Node Info: + value: + version: 6.0.13 + /bid-suggestion: + get: + tags: + - old + summary: Get Bid Suggestion + description: Get bid suggestion based on provided parameters. + operationId: getBidSuggestion + parameters: + - name: blockchain + in: query + schema: + type: string + example: hardhat + - name: epochsNumber + in: query + schema: + type: string + example: '5' + - name: assertionSize + in: query + schema: + type: string + example: '299' + - name: contentAssetStorageAddress + in: query + schema: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + - name: firstAssertionId + in: query + schema: + type: string + example: '0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf' + - name: hashFunctionId + in: query + schema: + type: string + example: '1' + requestBody: + content: + text/plain: + example: '' + responses: + '200': + description: Get Bid Suggestion + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '38' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 12:42:31 GMT + ETag: + schema: + type: string + example: W/"26-UrjseieOcIBnowM9obJae/FG7xc" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + bidSuggestion: + type: string + example: '903051579928002449' + examples: + Get Bid Suggestion: + value: + bidSuggestion: '903051579928002449' + /local-store: + post: + tags: + - old + summary: Local Store + description: Store locally. + operationId: localStore + requestBody: + content: + application/json: + schema: + type: array + items: + type: object + properties: + assertion: + type: array + items: + type: string + example: . + example: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: + type: string + example: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: + type: string + example: hardhat + contract: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: + type: string + example: TRIPLE + tokenId: + type: number + example: 0 + example: + - assertion: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + - assertion: + - '11000' . + - 'Belgrade' . + - 'Smith' . + - 'Adam' . + assertionId: >- + 0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9 + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + example: + - assertion: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + - assertion: + - '11000' . + - 'Belgrade' . + - 'Smith' . + - 'Adam' . + assertionId: >- + 0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9 + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + responses: + '202': + description: Local Store + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 12:49:45 GMT + ETag: + schema: + type: string + example: W/"36-uF3l7SNXwSBVObRCAJxOmp8OJGc" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 7d499975-ce42-4d84-9092-0ac2a62f5151 + examples: + Local Store: + value: + operationId: 7d499975-ce42-4d84-9092-0ac2a62f5151 + /publish: + post: + tags: + - old + summary: Publish Knowledge Asset + description: Publish assertion. + operationId: publishKnowledgeAsset + requestBody: + content: + application/json: + schema: + type: object + properties: + assertion: + type: array + items: + type: string + example: . + example: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: + type: string + example: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: + type: string + example: hardhat + contract: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: + type: number + example: 1 + tokenId: + type: number + example: 0 + example: + assertion: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: 1 + tokenId: 0 + responses: + '202': + description: Publish Knowledge Asset + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:07:57 GMT + ETag: + schema: + type: string + example: W/"36-SQS1f7vf+HLSUHZ6wvE9UUwksSY" + Keep-Alive: + schema: + type: string + example: timeout=5 + RateLimit-Limit: + schema: + type: string + example: '10' + RateLimit-Remaining: + schema: + type: string + example: '9' + RateLimit-Reset: + schema: + type: string + example: '22' + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 8270c131-91b8-4573-a69e-504ff388a8b6 + examples: + Publish Knowledge Asset: + value: + operationId: 8270c131-91b8-4573-a69e-504ff388a8b6 + /get: + post: + tags: + - old + summary: Get Knowledge Asset + description: Get an assertion. + operationId: getKnowledgeAsset + requestBody: + content: + application/json: + schema: + type: object + properties: + hashFunctionId: + type: number + example: 1 + id: + type: string + example: did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0 + state: + type: string + example: LATEST + example: + hashFunctionId: 1 + id: did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0 + state: LATEST + responses: + '202': + description: Get Knowledge Asset + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:16:39 GMT + ETag: + schema: + type: string + example: W/"36-tXDgcL88Mx02VotKK9H3zPuWwf8" + Keep-Alive: + schema: + type: string + example: timeout=5 + RateLimit-Limit: + schema: + type: string + example: '10' + RateLimit-Remaining: + schema: + type: string + example: '9' + RateLimit-Reset: + schema: + type: string + example: '12' + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 3a6df062-b3ce-4cac-aefa-77b1e8b9a4db + examples: + Get Knowledge Asset: + value: + operationId: 3a6df062-b3ce-4cac-aefa-77b1e8b9a4db + /update: + post: + tags: + - old + summary: Update Knowledge Asset + description: Update assertion. + operationId: updateKnowledgeAsset + requestBody: + content: + application/json: + schema: + type: object + properties: + assertion: + type: array + items: + type: string + example: . + example: + - . + - 'TL' . + - . + - >- + _:c14n0 + + '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' + . + assertionId: + type: string + example: >- + 0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0 + blockchain: + type: string + example: hardhat + contract: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: + type: number + example: 1 + tokenId: + type: number + example: 0 + example: + assertion: + - . + - 'TL' . + - . + - >- + _:c14n0 + + '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' + . + assertionId: >- + 0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0 + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: 1 + tokenId: 0 + responses: + '202': + description: Update Knowledge Asset + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:17:54 GMT + ETag: + schema: + type: string + example: W/"36-CjvPRlFINYIIcvR2H5gFBcOkNH8" + Keep-Alive: + schema: + type: string + example: timeout=5 + RateLimit-Limit: + schema: + type: string + example: '10' + RateLimit-Remaining: + schema: + type: string + example: '9' + RateLimit-Reset: + schema: + type: string + example: '57' + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 0d4c3efc-0f0b-435d-b9a3-402748dbbb2f + examples: + Update Knowledge Asset: + value: + operationId: 0d4c3efc-0f0b-435d-b9a3-402748dbbb2f + /query: + post: + tags: + - old + summary: Query DKG + description: Execute a query. + operationId: queryDkg + requestBody: + content: + application/json: + schema: + type: object + properties: + query: + type: string + example: >- + CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH + + { ?s ?p ?o . }}} + repository: + type: string + example: privateCurrent + type: + type: string + example: CONSTRUCT + example: + query: >- + CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH + + { ?s ?p ?o . }}} + repository: privateCurrent + type: CONSTRUCT + responses: + '202': + description: Query DKG + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:20:16 GMT + ETag: + schema: + type: string + example: W/"36-WRBDN6AcKKCbVi3DGfI6FvESm5w" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 746992ba-e607-4858-8deb-5cffc2541859 + examples: + Query DKG: + value: + operationId: 746992ba-e607-4858-8deb-5cffc2541859 + /{operation}/{operationId}: + get: + tags: + - v0 + summary: '[v0] Get Operation Result' + description: Get result of a specific operation by its ID. + operationId: v0GetOperationResult + responses: + '200': + description: '' + parameters: + - name: operation + in: path + required: true + schema: + type: string + - name: operationId + in: path + required: true + schema: + type: string + /v0/info: + get: + tags: + - v0 + summary: '[v0] Node Info' + description: Get the node information. + operationId: v0NodeInfo + responses: + '200': + description: '[v0] Node Info' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '20' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:27:58 GMT + ETag: + schema: + type: string + example: W/"14-Rq/28W5aGKCGXmXfM1+eW1LAbb4" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + version: + type: string + example: 6.0.13 + examples: + '[v0] Node Info': + value: + version: 6.0.13 + /v0/bid-suggestion: + get: + tags: + - v0 + summary: '[v0] Get Bid Suggestion' + description: Get bid suggestion based on provided parameters. + operationId: v0GetBidSuggestion + parameters: + - name: blockchain + in: query + schema: + type: string + example: hardhat + - name: epochsNumber + in: query + schema: + type: string + example: '5' + - name: assertionSize + in: query + schema: + type: string + example: '299' + - name: contentAssetStorageAddress + in: query + schema: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + - name: firstAssertionId + in: query + schema: + type: string + example: '0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf' + - name: hashFunctionId + in: query + schema: + type: string + example: '1' + requestBody: + content: + text/plain: + example: '' + responses: + '200': + description: '[v0] Get Bid Suggestion' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '39' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:59:02 GMT + ETag: + schema: + type: string + example: W/"27-ieFm/6t4DZwm0kFCMq71s37uy/g" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + bidSuggestion: + type: string + example: '1122511549276000025' + examples: + '[v0] Get Bid Suggestion': + value: + bidSuggestion: '1122511549276000025' + /v0/local-store: + post: + tags: + - v0 + summary: '[v0] Local Store' + description: Store locally. + operationId: v0LocalStore + requestBody: + content: + application/json: + schema: + type: array + items: + type: object + properties: + assertion: + type: array + items: + type: string + example: . + example: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: + type: string + example: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: + type: string + example: hardhat + contract: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: + type: string + example: TRIPLE + tokenId: + type: number + example: 0 + example: + - assertion: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + - assertion: + - '11000' . + - 'Belgrade' . + - 'Smith' . + - 'Adam' . + assertionId: >- + 0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9 + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + example: + - assertion: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + - assertion: + - '11000' . + - 'Belgrade' . + - 'Smith' . + - 'Adam' . + assertionId: >- + 0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9 + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + storeType: TRIPLE + tokenId: 0 + responses: + '202': + description: '[v0] Local Store' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:59:11 GMT + ETag: + schema: + type: string + example: W/"36-fpQtTlhbbWO7tqbMGm3CkKmOqaI" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 0a4ee669-95bb-41cd-a2e8-3382361e80d9 + examples: + '[v0] Local Store': + value: + operationId: 0a4ee669-95bb-41cd-a2e8-3382361e80d9 + /v0/publish: + post: + tags: + - v0 + summary: '[v0] Publish Knowledge Asset' + description: Publish assertion. + operationId: v0PublishKnowledgeAsset + requestBody: + content: + application/json: + schema: + type: object + properties: + assertion: + type: array + items: + type: string + example: . + example: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: + type: string + example: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: + type: string + example: hardhat + contract: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: + type: number + example: 1 + tokenId: + type: number + example: 0 + example: + assertion: + - . + - 'OT' . + - . + - >- + _:c14n0 + + '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' + . + assertionId: >- + 0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: 1 + tokenId: 0 + responses: + '202': + description: '[v0] Publish Knowledge Asset' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 13:59:54 GMT + ETag: + schema: + type: string + example: W/"36-wKIhHpa0/tdVYh1Y8D2yINolruA" + Keep-Alive: + schema: + type: string + example: timeout=5 + RateLimit-Limit: + schema: + type: string + example: '10' + RateLimit-Remaining: + schema: + type: string + example: '9' + RateLimit-Reset: + schema: + type: string + example: '52' + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 476fb996-db1a-47b8-8da4-80d71411feb3 + examples: + '[v0] Publish Knowledge Asset': + value: + operationId: 476fb996-db1a-47b8-8da4-80d71411feb3 + /v0/get: + post: + tags: + - v0 + summary: '[v0] Get Knowledge Asset' + description: Get an assertion. + operationId: v0GetKnowledgeAsset + requestBody: + content: + application/json: + schema: + type: object + properties: + hashFunctionId: + type: number + example: 1 + id: + type: string + example: did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0 + state: + type: string + example: LATEST + example: + hashFunctionId: 1 + id: did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0 + state: LATEST + responses: + '202': + description: '[v0] Get Knowledge Asset' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 14:00:02 GMT + ETag: + schema: + type: string + example: W/"36-/27PH/ZH74wwVBrYDxWSzCk4yA0" + Keep-Alive: + schema: + type: string + example: timeout=5 + RateLimit-Limit: + schema: + type: string + example: '10' + RateLimit-Remaining: + schema: + type: string + example: '9' + RateLimit-Reset: + schema: + type: string + example: '44' + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 5b34c048-2d08-4696-b3c4-c37c831b89ce + examples: + '[v0] Get Knowledge Asset': + value: + operationId: 5b34c048-2d08-4696-b3c4-c37c831b89ce + /v0/update: + post: + tags: + - v0 + summary: '[v0] Update Knowledge Asset' + description: Update assertion. + operationId: v0UpdateKnowledgeAsset + requestBody: + content: + application/json: + schema: + type: object + properties: + assertion: + type: array + items: + type: string + example: . + example: + - . + - 'TL' . + - . + - >- + _:c14n0 + + '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' + . + assertionId: + type: string + example: >- + 0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0 + blockchain: + type: string + example: hardhat + contract: + type: string + example: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: + type: number + example: 1 + tokenId: + type: number + example: 0 + example: + assertion: + - . + - 'TL' . + - . + - >- + _:c14n0 + + '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' + . + assertionId: >- + 0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0 + blockchain: hardhat + contract: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07' + hashFunctionId: 1 + tokenId: 0 + responses: + '202': + description: '[v0] Update Knowledge Asset' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 14:00:09 GMT + ETag: + schema: + type: string + example: W/"36-77qAdgCc/SEN47aETAww86PM04w" + Keep-Alive: + schema: + type: string + example: timeout=5 + RateLimit-Limit: + schema: + type: string + example: '10' + RateLimit-Remaining: + schema: + type: string + example: '9' + RateLimit-Reset: + schema: + type: string + example: '38' + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: f0d34032-6910-49b4-a2a8-71c9f58feb58 + examples: + '[v0] Update Knowledge Asset': + value: + operationId: f0d34032-6910-49b4-a2a8-71c9f58feb58 + /v0/query: + post: + tags: + - v0 + summary: '[v0] Query DKG' + description: Execute a query. + operationId: v0QueryDkg + requestBody: + content: + application/json: + schema: + type: object + properties: + query: + type: string + example: >- + CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH + + { ?s ?p ?o . }}} + repository: + type: string + example: privateCurrent + type: + type: string + example: CONSTRUCT + example: + query: >- + CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH + + { ?s ?p ?o . }}} + repository: privateCurrent + type: CONSTRUCT + responses: + '202': + description: '[v0] Query DKG' + headers: + Access-Control-Allow-Origin: + schema: + type: string + example: '*' + Connection: + schema: + type: string + example: keep-alive + Content-Length: + schema: + type: string + example: '54' + Date: + schema: + type: string + example: Thu, 17 Aug 2023 14:00:19 GMT + ETag: + schema: + type: string + example: W/"36-kqaRe64EoJygoEadXJWRekiCs4s" + Keep-Alive: + schema: + type: string + example: timeout=5 + X-Powered-By: + schema: + type: string + example: Express + content: + application/json: + schema: + type: object + properties: + operationId: + type: string + example: 4d371ffb-a620-452f-8d16-3e427bafeae2 + examples: + '[v0] Query DKG': + value: + operationId: 4d371ffb-a620-452f-8d16-3e427bafeae2 +tags: + - name: old + - name: v0 diff --git a/docs/postman/DKGv6.postman_collection.json b/docs/postman/DKGv6.postman_collection.json new file mode 100644 index 0000000000..bd257955e4 --- /dev/null +++ b/docs/postman/DKGv6.postman_collection.json @@ -0,0 +1,1774 @@ +{ + "info": { + "_postman_id": "550b0443-cd47-482a-9c56-2b1229422426", + "name": "DKGv6", + "description": "DKG v6 API Collection.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "old", + "item": [ + { + "name": "Node Info", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "url": { + "raw": "{{host}}:{{port}}/info", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "info" + ] + }, + "description": "Get the node information." + }, + "response": [ + { + "name": "Node Info", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "url": { + "raw": "{{host}}:{{port}}/info", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "info" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "20" + }, + { + "key": "ETag", + "value": "W/\"14-Rq/28W5aGKCGXmXfM1+eW1LAbb4\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 12:43:07 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"version\": \"6.0.13\"\n}" + } + ] + }, + { + "name": "Get Bid Suggestion", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{host}}:{{port}}/bid-suggestion?blockchain={{blockchain}}&epochsNumber={{epochsNumber}}&assertionSize={{assertionSize}}&contentAssetStorageAddress={{contentAssetStorageAddress}}&firstAssertionId={{firstAssertionId}}&hashFunctionId={{hashFunctionId}}", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "bid-suggestion" + ], + "query": [ + { + "key": "blockchain", + "value": "{{blockchain}}" + }, + { + "key": "epochsNumber", + "value": "{{epochsNumber}}" + }, + { + "key": "assertionSize", + "value": "{{assertionSize}}" + }, + { + "key": "contentAssetStorageAddress", + "value": "{{contentAssetStorageAddress}}" + }, + { + "key": "firstAssertionId", + "value": "{{firstAssertionId}}" + }, + { + "key": "hashFunctionId", + "value": "{{hashFunctionId}}" + } + ] + }, + "description": "Get bid suggestion based on provided parameters." + }, + "response": [ + { + "name": "Get Bid Suggestion", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{host}}:{{port}}/bid-suggestion?blockchain={{blockchain}}&epochsNumber={{epochsNumber}}&assertionSize={{assertionSize}}&contentAssetStorageAddress={{contentAssetStorageAddress}}&firstAssertionId={{firstAssertionId}}&hashFunctionId={{hashFunctionId}}", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "bid-suggestion" + ], + "query": [ + { + "key": "blockchain", + "value": "{{blockchain}}" + }, + { + "key": "epochsNumber", + "value": "{{epochsNumber}}" + }, + { + "key": "assertionSize", + "value": "{{assertionSize}}" + }, + { + "key": "contentAssetStorageAddress", + "value": "{{contentAssetStorageAddress}}" + }, + { + "key": "firstAssertionId", + "value": "{{firstAssertionId}}" + }, + { + "key": "hashFunctionId", + "value": "{{hashFunctionId}}" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "38" + }, + { + "key": "ETag", + "value": "W/\"26-UrjseieOcIBnowM9obJae/FG7xc\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 12:42:31 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"bidSuggestion\": \"903051579928002449\"\n}" + } + ] + }, + { + "name": "Local Store", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{{assertions}}" + }, + "url": { + "raw": "{{host}}:{{port}}/local-store", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "local-store" + ] + }, + "description": "Store locally." + }, + "response": [ + { + "name": "Local Store", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{{assertions}}" + }, + "url": { + "raw": "{{host}}:{{port}}/local-store", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "local-store" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-uF3l7SNXwSBVObRCAJxOmp8OJGc\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 12:49:45 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"7d499975-ce42-4d84-9092-0ac2a62f5151\"\n}" + } + ] + }, + { + "name": "Publish Knowledge Asset", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf\",\n \"assertion\": [\n \" .\",\n \" 'OT' .\",\n \" .\",\n \"_:c14n0 '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/publish", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "publish" + ] + }, + "description": "Publish assertion." + }, + "response": [ + { + "name": "Publish Knowledge Asset", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf\",\n \"assertion\": [\n \" .\",\n \" 'OT' .\",\n \" .\",\n \"_:c14n0 '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/publish", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "publish" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "RateLimit-Limit", + "value": "10" + }, + { + "key": "RateLimit-Remaining", + "value": "9" + }, + { + "key": "RateLimit-Reset", + "value": "22" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-SQS1f7vf+HLSUHZ6wvE9UUwksSY\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:07:57 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"8270c131-91b8-4573-a69e-504ff388a8b6\"\n}" + } + ] + }, + { + "name": "Get Knowledge Asset", + "protocolProfileBehavior": { + "disabledSystemHeaders": {} + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0\",\n \"state\": \"LATEST\",\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/get", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "get" + ] + }, + "description": "Get an assertion." + }, + "response": [ + { + "name": "Get Knowledge Asset", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0\",\n \"state\": \"LATEST\",\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/get", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "get" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "RateLimit-Limit", + "value": "10" + }, + { + "key": "RateLimit-Remaining", + "value": "9" + }, + { + "key": "RateLimit-Reset", + "value": "12" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-tXDgcL88Mx02VotKK9H3zPuWwf8\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:16:39 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"3a6df062-b3ce-4cac-aefa-77b1e8b9a4db\"\n}" + } + ] + }, + { + "name": "Update Knowledge Asset", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0\",\n \"assertion\": [\n \" .\",\n \" 'TL' .\",\n \" .\",\n \"_:c14n0 '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/update", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "update" + ] + }, + "description": "Update assertion." + }, + "response": [ + { + "name": "Update Knowledge Asset", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0\",\n \"assertion\": [\n \" .\",\n \" 'TL' .\",\n \" .\",\n \"_:c14n0 '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/update", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "update" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "RateLimit-Limit", + "value": "10" + }, + { + "key": "RateLimit-Remaining", + "value": "9" + }, + { + "key": "RateLimit-Reset", + "value": "57" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-CjvPRlFINYIIcvR2H5gFBcOkNH8\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:17:54 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"0d4c3efc-0f0b-435d-b9a3-402748dbbb2f\"\n}" + } + ] + }, + { + "name": "Query DKG", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"query\": \"CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH { ?s ?p ?o . }}}\",\n \"type\": \"CONSTRUCT\",\n \"repository\": \"privateCurrent\"\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/query", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "query" + ] + }, + "description": "Execute a query." + }, + "response": [ + { + "name": "Query DKG", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"query\": \"CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH { ?s ?p ?o . }}}\",\n \"type\": \"CONSTRUCT\",\n \"repository\": \"privateCurrent\"\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/query", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "query" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-WRBDN6AcKKCbVi3DGfI6FvESm5w\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:20:16 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"746992ba-e607-4858-8deb-5cffc2541859\"\n}" + } + ] + }, + { + "name": "Get Operation Result", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "url": { + "raw": "{{host}}:{{port}}/{{operation}}/{{operationId}}", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "{{operation}}", + "{{operationId}}" + ] + }, + "description": "Get result of a specific operation by its ID." + }, + "response": [] + } + ] + }, + { + "name": "v0", + "item": [ + { + "name": "[v0] Node Info", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "url": { + "raw": "{{host}}:{{port}}/v0/info", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "info" + ] + }, + "description": "Get the node information." + }, + "response": [ + { + "name": "[v0] Node Info", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "url": { + "raw": "{{host}}:{{port}}/v0/info", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "info" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "20" + }, + { + "key": "ETag", + "value": "W/\"14-Rq/28W5aGKCGXmXfM1+eW1LAbb4\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:27:58 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"version\": \"6.0.13\"\n}" + } + ] + }, + { + "name": "[v0] Get Bid Suggestion", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/bid-suggestion?blockchain={{blockchain}}&epochsNumber={{epochsNumber}}&assertionSize={{assertionSize}}&contentAssetStorageAddress={{contentAssetStorageAddress}}&firstAssertionId={{firstAssertionId}}&hashFunctionId={{hashFunctionId}}", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "bid-suggestion" + ], + "query": [ + { + "key": "blockchain", + "value": "{{blockchain}}" + }, + { + "key": "epochsNumber", + "value": "{{epochsNumber}}" + }, + { + "key": "assertionSize", + "value": "{{assertionSize}}" + }, + { + "key": "contentAssetStorageAddress", + "value": "{{contentAssetStorageAddress}}" + }, + { + "key": "firstAssertionId", + "value": "{{firstAssertionId}}" + }, + { + "key": "hashFunctionId", + "value": "{{hashFunctionId}}" + } + ] + }, + "description": "Get bid suggestion based on provided parameters." + }, + "response": [ + { + "name": "[v0] Get Bid Suggestion", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/bid-suggestion?blockchain={{blockchain}}&epochsNumber={{epochsNumber}}&assertionSize={{assertionSize}}&contentAssetStorageAddress={{contentAssetStorageAddress}}&firstAssertionId={{firstAssertionId}}&hashFunctionId={{hashFunctionId}}", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "bid-suggestion" + ], + "query": [ + { + "key": "blockchain", + "value": "{{blockchain}}" + }, + { + "key": "epochsNumber", + "value": "{{epochsNumber}}" + }, + { + "key": "assertionSize", + "value": "{{assertionSize}}" + }, + { + "key": "contentAssetStorageAddress", + "value": "{{contentAssetStorageAddress}}" + }, + { + "key": "firstAssertionId", + "value": "{{firstAssertionId}}" + }, + { + "key": "hashFunctionId", + "value": "{{hashFunctionId}}" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "39" + }, + { + "key": "ETag", + "value": "W/\"27-ieFm/6t4DZwm0kFCMq71s37uy/g\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:59:02 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"bidSuggestion\": \"1122511549276000025\"\n}" + } + ] + }, + { + "name": "[v0] Local Store", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{{assertions}}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/local-store", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "local-store" + ] + }, + "description": "Store locally." + }, + "response": [ + { + "name": "[v0] Local Store", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{{assertions}}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/local-store", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "local-store" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-fpQtTlhbbWO7tqbMGm3CkKmOqaI\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:59:11 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"0a4ee669-95bb-41cd-a2e8-3382361e80d9\"\n}" + } + ] + }, + { + "name": "[v0] Publish Knowledge Asset", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf\",\n \"assertion\": [\n \" .\",\n \" 'OT' .\",\n \" .\",\n \"_:c14n0 '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/publish", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "publish" + ] + }, + "description": "Publish assertion." + }, + "response": [ + { + "name": "[v0] Publish Knowledge Asset", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf\",\n \"assertion\": [\n \" .\",\n \" 'OT' .\",\n \" .\",\n \"_:c14n0 '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/publish", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "publish" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "RateLimit-Limit", + "value": "10" + }, + { + "key": "RateLimit-Remaining", + "value": "9" + }, + { + "key": "RateLimit-Reset", + "value": "52" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-wKIhHpa0/tdVYh1Y8D2yINolruA\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 13:59:54 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"476fb996-db1a-47b8-8da4-80d71411feb3\"\n}" + } + ] + }, + { + "name": "[v0] Get Knowledge Asset", + "protocolProfileBehavior": { + "disabledSystemHeaders": {} + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0\",\n \"state\": \"LATEST\",\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/get", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "get" + ] + }, + "description": "Get an assertion." + }, + "response": [ + { + "name": "[v0] Get Knowledge Asset", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0\",\n \"state\": \"LATEST\",\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/get", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "get" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "RateLimit-Limit", + "value": "10" + }, + { + "key": "RateLimit-Remaining", + "value": "9" + }, + { + "key": "RateLimit-Reset", + "value": "44" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-/27PH/ZH74wwVBrYDxWSzCk4yA0\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 14:00:02 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"5b34c048-2d08-4696-b3c4-c37c831b89ce\"\n}" + } + ] + }, + { + "name": "[v0] Update Knowledge Asset", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0\",\n \"assertion\": [\n \" .\",\n \" 'TL' .\",\n \" .\",\n \"_:c14n0 '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/update", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "update" + ] + }, + "description": "Update assertion." + }, + "response": [ + { + "name": "[v0] Update Knowledge Asset", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"assertionId\": \"0xef0adc464c3dcb1d353567db5972de8d47f44d6621326645324f9730f2c83cf0\",\n \"assertion\": [\n \" .\",\n \" 'TL' .\",\n \" .\",\n \"_:c14n0 '0xa3acb6d57097f316b973e9e33d303cf411b8d62d7d589576e348d0d7049e3b63' .\"\n ],\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"hashFunctionId\": 1\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/update", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "update" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "RateLimit-Limit", + "value": "10" + }, + { + "key": "RateLimit-Remaining", + "value": "9" + }, + { + "key": "RateLimit-Reset", + "value": "38" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-77qAdgCc/SEN47aETAww86PM04w\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 14:00:09 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"f0d34032-6910-49b4-a2a8-71c9f58feb58\"\n}" + } + ] + }, + { + "name": "[v0] Query DKG", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"query\": \"CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH { ?s ?p ?o . }}}\",\n \"type\": \"CONSTRUCT\",\n \"repository\": \"privateCurrent\"\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/query", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "query" + ] + }, + "description": "Execute a query." + }, + "response": [ + { + "name": "[v0] Query DKG", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"query\": \"CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH { ?s ?p ?o . }}}\",\n \"type\": \"CONSTRUCT\",\n \"repository\": \"privateCurrent\"\n}" + }, + "url": { + "raw": "{{host}}:{{port}}/v0/query", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "v0", + "query" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "54" + }, + { + "key": "ETag", + "value": "W/\"36-kqaRe64EoJygoEadXJWRekiCs4s\"" + }, + { + "key": "Date", + "value": "Thu, 17 Aug 2023 14:00:19 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"operationId\": \"4d371ffb-a620-452f-8d16-3e427bafeae2\"\n}" + } + ] + }, + { + "name": "[v0] Get Operation Result", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{authToken}}" + } + ], + "url": { + "raw": "{{host}}:{{port}}/{{operation}}/{{operationId}}", + "host": [ + "{{host}}" + ], + "port": "{{port}}", + "path": [ + "{{operation}}", + "{{operationId}}" + ] + }, + "description": "Get result of a specific operation by its ID." + }, + "response": [] + } + ] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{authToken}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "host", + "value": "localhost" + }, + { + "key": "port", + "value": "8900", + "type": "number" + }, + { + "key": "authToken", + "value": "", + "type": "string" + }, + { + "key": "blockchain", + "value": "hardhat" + }, + { + "key": "epochsNumber", + "value": "5" + }, + { + "key": "assertionSize", + "value": "299" + }, + { + "key": "contentAssetStorageAddress", + "value": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07" + }, + { + "key": "hashFunctionId", + "value": "1" + }, + { + "key": "firstAssertionId", + "value": "0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf" + }, + { + "key": "assertions", + "value": "[\n {\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"assertionId\": \"0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf\",\n \"assertion\": [\n \" .\",\n \" 'OT' .\",\n \" .\",\n \"_:c14n0 '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' .\"\n ],\n \"storeType\": \"TRIPLE\"\n },\n {\n \"blockchain\": \"hardhat\",\n \"contract\": \"0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07\",\n \"tokenId\": 0,\n \"assertionId\": \"0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9\",\n \"assertion\": [\n \" '11000' .\",\n \" 'Belgrade' .\",\n \" 'Smith' .\",\n \" 'Adam' .\"\n ],\n \"storeType\": \"TRIPLE\"\n }\n]", + "type": "string" + }, + { + "key": "assertionId", + "value": "0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf" + }, + { + "key": "assertion", + "value": "[\n \" .\",\n \" 'OT' .\",\n \" .\",\n \"_:c14n0 '0xcfab2d364fe01757d7a83d3b32284395d87b1c379adabb1e28a16666e0a4fca9' .\"\n]", + "type": "string" + }, + { + "key": "contract", + "value": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07" + }, + { + "key": "tokenId", + "value": "1" + }, + { + "key": "UAL", + "value": "did:dkg:hardhat/0xb0d4afd8879ed9f52b28595d31b441d079b2ca07/0" + }, + { + "key": "state", + "value": "LATEST" + }, + { + "key": "query", + "value": "CONSTRUCT { ?s ?p ?o } WHERE {{GRAPH { ?s ?p ?o . }}}" + }, + { + "key": "type", + "value": "CONSTRUCT" + }, + { + "key": "repository", + "value": "privateCurrent" + } + ] +} \ No newline at end of file diff --git a/images/banner.gif b/images/banner.gif new file mode 100644 index 0000000000..1157a572ff Binary files /dev/null and b/images/banner.gif differ diff --git a/images/dkg-architecture.png b/images/dkg-architecture.png new file mode 100644 index 0000000000..6d787d8163 Binary files /dev/null and b/images/dkg-architecture.png differ diff --git a/images/icons/coinmarketcap.svg b/images/icons/coinmarketcap.svg new file mode 100644 index 0000000000..30d702d700 --- /dev/null +++ b/images/icons/coinmarketcap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/icons/discord.svg b/images/icons/discord.svg new file mode 100644 index 0000000000..4257d772e3 --- /dev/null +++ b/images/icons/discord.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/images/icons/linkedin.svg b/images/icons/linkedin.svg new file mode 100644 index 0000000000..908c867517 --- /dev/null +++ b/images/icons/linkedin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/icons/medium.svg b/images/icons/medium.svg new file mode 100644 index 0000000000..ae6b3edf17 --- /dev/null +++ b/images/icons/medium.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/icons/reddit.svg b/images/icons/reddit.svg new file mode 100644 index 0000000000..57c919f016 --- /dev/null +++ b/images/icons/reddit.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/images/icons/telegram.svg b/images/icons/telegram.svg new file mode 100644 index 0000000000..d52f2e23d4 --- /dev/null +++ b/images/icons/telegram.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/images/icons/x.svg b/images/icons/x.svg new file mode 100644 index 0000000000..17bf45dca1 --- /dev/null +++ b/images/icons/x.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/icons/youtube.svg b/images/icons/youtube.svg new file mode 100644 index 0000000000..b9324915bf --- /dev/null +++ b/images/icons/youtube.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/images/ka.png b/images/ka.png new file mode 100644 index 0000000000..7381788ab9 Binary files /dev/null and b/images/ka.png differ diff --git a/images/knowledge-assets-graph1.svg b/images/knowledge-assets-graph1.svg new file mode 100644 index 0000000000..bf7d1fe7f1 --- /dev/null +++ b/images/knowledge-assets-graph1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/images/knowledge-assets-graph2.svg b/images/knowledge-assets-graph2.svg new file mode 100644 index 0000000000..654b0de877 --- /dev/null +++ b/images/knowledge-assets-graph2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/images/knowledge-assets-graph3.svg b/images/knowledge-assets-graph3.svg new file mode 100644 index 0000000000..4482eba946 --- /dev/null +++ b/images/knowledge-assets-graph3.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/images/knowledge-assets-graph4.svg b/images/knowledge-assets-graph4.svg new file mode 100644 index 0000000000..4f30cddb9f --- /dev/null +++ b/images/knowledge-assets-graph4.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/images/nodes.png b/images/nodes.png new file mode 100644 index 0000000000..fac3e0b4ca Binary files /dev/null and b/images/nodes.png differ diff --git a/images/sdk.png b/images/sdk.png new file mode 100644 index 0000000000..4137e15bb4 Binary files /dev/null and b/images/sdk.png differ diff --git a/index.js b/index.js index 7a6cda7eef..fdc26099db 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,6 @@ /* eslint-disable no-console */ import 'dotenv/config'; import fs from 'fs-extra'; -import path from 'path'; -import appRootPath from 'app-root-path'; -import { execSync } from 'child_process'; -import semver from 'semver'; import OTNode from './ot-node.js'; import { NODE_ENVIRONMENTS } from './src/constants/constants.js'; @@ -30,26 +26,26 @@ process.env.NODE_ENV = await node.start(); } catch (e) { console.error(`Error occurred while start ot-node, error message: ${e}. ${e.stack}`); - console.error(`Trying to recover from older version`); - if (process.env.NODE_ENV !== NODE_ENVIRONMENTS.DEVELOPMENT) { - const rootPath = path.join(appRootPath.path, '..'); - const oldVersionsDirs = (await fs.promises.readdir(rootPath, { withFileTypes: true })) - .filter((dirent) => dirent.isDirectory()) - .map((dirent) => dirent.name) - .filter((name) => semver.valid(name) && !appRootPath.path.includes(name)); - - if (oldVersionsDirs.length === 0) { - console.error( - `Failed to start OT-Node, no backup code available. Error message: ${e.message}`, - ); - process.exit(1); - } - - const oldVersion = oldVersionsDirs.sort(semver.compare).pop(); - const oldversionPath = path.join(rootPath, oldVersion); - execSync(`ln -sfn ${oldversionPath} ${rootPath}/current`); - await fs.promises.rm(appRootPath.path, { force: true, recursive: true }); - } + // console.error(`Trying to recover from older version`); + // if (process.env.NODE_ENV !== NODE_ENVIRONMENTS.DEVELOPMENT) { + // const rootPath = path.join(appRootPath.path, '..'); + // const oldVersionsDirs = (await fs.promises.readdir(rootPath, { withFileTypes: true })) + // .filter((dirent) => dirent.isDirectory()) + // .map((dirent) => dirent.name) + // .filter((name) => semver.valid(name) && !appRootPath.path.includes(name)); + // + // if (oldVersionsDirs.length === 0) { + // console.error( + // `Failed to start OT-Node, no backup code available. Error message: ${e.message}`, + // ); + // process.exit(1); + // } + // + // const oldVersion = oldVersionsDirs.sort(semver.compare).pop(); + // const oldversionPath = path.join(rootPath, oldVersion); + // execSync(`ln -sfn ${oldversionPath} ${rootPath}/current`); + // await fs.promises.rm(appRootPath.path, { force: true, recursive: true }); + // } process.exit(1); } })(); diff --git a/installer/installer.sh b/installer/installer.sh index ba6a78771b..b9d090e96d 100755 --- a/installer/installer.sh +++ b/installer/installer.sh @@ -87,7 +87,7 @@ install_prereqs() { rm -rf setup_$NODEJS_VER.x perform_step apt update "Updating Ubuntu package repository" perform_step apt-get install nodejs -y "Installing node.js" - perform_step npm install -g npm "Installing npm" + perform_step npm install -g npm@^8 "Installing npm" perform_step install_firewall "Configuring firewall" perform_step apt remove unattended-upgrades -y "Remove unattended upgrades" } @@ -263,9 +263,9 @@ install_node() { perform_step touch $CONFIG_DIR/.origintrail_noderc "Configuring node config file" perform_step $(jq --null-input --arg tripleStore "$tripleStore" '{"logLevel": "trace", "auth": {"ipWhitelist": ["::1", "127.0.0.1"]}}' > $CONFIG_DIR/.origintrail_noderc) "Adding loglevel and auth values to node config file" - perform_step $(jq --arg tripleStore "$tripleStore" --arg tripleStoreUrl "$tripleStoreUrl" '.modules.tripleStore.implementation[$tripleStore] |= + perform_step $(jq --arg tripleStore "$tripleStore" --arg tripleStoreUrl "$tripleStoreUrl" '.modules.tripleStore.implementation[$tripleStore] |= { - "enabled": "true", + "enabled": "true", "config": { "repositories": { "privateCurrent": { @@ -293,24 +293,24 @@ install_node() { "password": "" } } - } + } } + .' $CONFIG_DIR/.origintrail_noderc > $CONFIG_DIR/origintrail_noderc_tmp) "Adding node wallets to node config file 1/2" perform_step mv $CONFIG_DIR/origintrail_noderc_tmp $CONFIG_DIR/.origintrail_noderc "Adding node wallets to node config file 2/2" - - perform_step $(jq --arg blockchain "otp" --arg evmOperationalWallet "$EVM_OPERATIONAL_WALLET" --arg evmOperationalWalletPrivateKey "$EVM_OPERATIONAL_PRIVATE_KEY" --arg evmManagementWallet "$EVM_MANAGEMENT_WALLET" --arg evmManagementWallet "$SHARES_TOKEN_NAME" --arg evmManagementWallet "$SHARES_TOKEN_SYMBOL" --arg sharesTokenName "$SHARES_TOKEN_NAME" --arg sharesTokenSymbol "$SHARES_TOKEN_SYMBOL" '.modules.blockchain.implementation[$blockchain].config |= - { - "evmOperationalWalletPublicKey": $evmOperationalWallet, - "evmOperationalWalletPrivateKey": $evmOperationalWalletPrivateKey, - "evmManagementWalletPublicKey": $evmManagementWallet, - "sharesTokenName": $sharesTokenName, + + perform_step $(jq --arg blockchain "otp" --arg evmOperationalWallet "$EVM_OPERATIONAL_WALLET" --arg evmOperationalWalletPrivateKey "$EVM_OPERATIONAL_PRIVATE_KEY" --arg evmManagementWallet "$EVM_MANAGEMENT_WALLET" --arg evmManagementWallet "$SHARES_TOKEN_NAME" --arg evmManagementWallet "$SHARES_TOKEN_SYMBOL" --arg sharesTokenName "$SHARES_TOKEN_NAME" --arg sharesTokenSymbol "$SHARES_TOKEN_SYMBOL" '.modules.blockchain.implementation[$blockchain].config |= + { + "evmOperationalWalletPublicKey": $evmOperationalWallet, + "evmOperationalWalletPrivateKey": $evmOperationalWalletPrivateKey, + "evmManagementWalletPublicKey": $evmManagementWallet, + "sharesTokenName": $sharesTokenName, "sharesTokenSymbol": $sharesTokenSymbol } + .' $CONFIG_DIR/.origintrail_noderc > $CONFIG_DIR/origintrail_noderc_tmp) "Adding node wallets to node config file 1/2" - + perform_step mv $CONFIG_DIR/origintrail_noderc_tmp $CONFIG_DIR/.origintrail_noderc "Adding node wallets to node config file 2/2" perform_step cp $OTNODE_DIR/installer/data/otnode.service /lib/systemd/system/ "Copying otnode service file" - + systemctl daemon-reload perform_step systemctl enable otnode "Enabling otnode" perform_step systemctl start otnode "Starting otnode" @@ -411,4 +411,4 @@ If the logs do not show and the screen hangs, press ctrl+c to exit the installat " read -p "Press enter to continue..." -journalctl -u otnode --output cat -fn 200 \ No newline at end of file +journalctl -u otnode --output cat -fn 200 diff --git a/ot-node.js b/ot-node.js index 5e89a6b99f..deff16483c 100644 --- a/ot-node.js +++ b/ot-node.js @@ -5,19 +5,11 @@ import { createRequire } from 'module'; import { execSync } from 'child_process'; import DependencyInjection from './src/service/dependency-injection.js'; import Logger from './src/logger/logger.js'; -import { MIN_NODE_VERSION, NODE_ENVIRONMENTS } from './src/constants/constants.js'; +import { MIN_NODE_VERSION } from './src/constants/constants.js'; import FileService from './src/service/file-service.js'; import OtnodeUpdateCommand from './src/commands/common/otnode-update-command.js'; import OtAutoUpdater from './src/modules/auto-updater/implementation/ot-auto-updater.js'; -import PullBlockchainShardingTableMigration from './src/migration/pull-sharding-table-migration.js'; -import TripleStoreUserConfigurationMigration from './src/migration/triple-store-user-configuration-migration.js'; -import PrivateAssetsMetadataMigration from './src/migration/private-assets-metadata-migration.js'; -import ServiceAgreementsMetadataMigration from './src/migration/service-agreements-metadata-migration.js'; -import RemoveAgreementStartEndTimeMigration from './src/migration/remove-agreement-start-end-time-migration.js'; -import MarkOldBlockchainEventsAsProcessedMigration from './src/migration/mark-old-blockchain-events-as-processed-migration.js'; -import TripleStoreMetadataMigration from './src/migration/triple-store-metadata-migration.js'; -import RemoveOldEpochCommandsMigration from './src/migration/remove-old-epoch-commands-migration.js'; -import PendingStorageMigration from './src/migration/pending-storage-migration.js'; +import MigrationExecutor from './src/migration/migration-executor.js'; const require = createRequire(import.meta.url); const pjson = require('./package.json'); @@ -35,7 +27,14 @@ class OTNode { async start() { await this.checkForUpdate(); await this.removeUpdateFile(); - await this.executeTripleStoreUserConfigurationMigration(); + await MigrationExecutor.executeTripleStoreUserConfigurationMigration( + this.logger, + this.config, + ); + await MigrationExecutor.executeTelemetryModuleUserConfigurationMigration( + this.logger, + this.config, + ); this.logger.info(' β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—'); this.logger.info('β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•'); this.logger.info('β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—'); @@ -52,24 +51,57 @@ class OTNode { this.initializeEventEmitter(); await this.initializeModules(); - await this.executePullShardingTableMigration(); - await this.executePrivateAssetsMetadataMigration(); - await this.executeRemoveAgreementStartEndTimeMigration(); - await this.executeMarkOldBlockchainEventsAsProcessedMigration(); - await this.executeTripleStoreMetadataMigration(); - await this.executeServiceAgreementsMetadataMigration(); - await this.executeRemoveOldEpochCommandsMigration(); - await this.executePendingStorageMigration(); - + await MigrationExecutor.executePullShardingTableMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executePrivateAssetsMetadataMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executeRemoveAgreementStartEndTimeMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executeMarkOldBlockchainEventsAsProcessedMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executeTripleStoreMetadataMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executeServiceAgreementsMetadataMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executeRemoveOldEpochCommandsMigration( + this.container, + this.logger, + this.config, + ); + await MigrationExecutor.executePendingStorageMigration(this.logger, this.config); + await MigrationExecutor.executeServiceAgreementsOpDatabaseMigration( + this.container, + this.logger, + this.config, + ); await this.createProfiles(); + await this.initializeCommandExecutor(); await this.initializeShardingTableService(); - await this.initializeTelemetryInjectionService(); await this.initializeBlockchainEventListenerService(); - await this.initializeCommandExecutor(); await this.initializeRouters(); await this.startNetworkModule(); + this.startTelemetryModule(); + this.resumeCommandExecutor(); this.logger.info('Node is up and running!'); } @@ -244,9 +276,11 @@ class OTNode { async initializeCommandExecutor() { try { const commandExecutor = this.container.resolve('commandExecutor'); - await commandExecutor.init(); - commandExecutor.replay(); - await commandExecutor.start(); + commandExecutor.pauseQueue(); + await commandExecutor.addDefaultCommands(); + commandExecutor + .replayOldCommands() + .then(() => this.logger.info('Finished replaying old commands')); } catch (e) { this.logger.error( `Command executor initialization failed. Error message: ${e.message}`, @@ -255,195 +289,36 @@ class OTNode { } } - async startNetworkModule() { - const networkModuleManager = this.container.resolve('networkModuleManager'); - await networkModuleManager.start(); - } - - async executePrivateAssetsMetadataMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - const blockchainModuleManager = this.container.resolve('blockchainModuleManager'); - const tripleStoreService = this.container.resolve('tripleStoreService'); - const serviceAgreementService = this.container.resolve('serviceAgreementService'); - const ualService = this.container.resolve('ualService'); - const dataService = this.container.resolve('dataService'); - - const migration = new PrivateAssetsMetadataMigration( - 'privateAssetsMetadataMigration', - this.logger, - this.config, - tripleStoreService, - blockchainModuleManager, - serviceAgreementService, - ualService, - dataService, - ); - - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - this.logger.info('Node will now restart!'); - this.stop(1); - } - } - - async executeTripleStoreUserConfigurationMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - - const migration = new TripleStoreUserConfigurationMigration( - 'tripleStoreUserConfigurationMigration', - this.logger, - this.config, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - this.logger.info('Node will now restart!'); + resumeCommandExecutor() { + try { + const commandExecutor = this.container.resolve('commandExecutor'); + commandExecutor.resumeQueue(); + } catch (e) { + this.logger.error( + `Unable to resume command executor queue. Error message: ${e.message}`, + ); this.stop(1); } } - async executePullShardingTableMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - - const blockchainModuleManager = this.container.resolve('blockchainModuleManager'); - const repositoryModuleManager = this.container.resolve('repositoryModuleManager'); - const validationModuleManager = this.container.resolve('validationModuleManager'); - - const migration = new PullBlockchainShardingTableMigration( - 'pullShardingTableMigrationV612', - this.logger, - this.config, - repositoryModuleManager, - blockchainModuleManager, - validationModuleManager, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } - } - - async executeServiceAgreementsMetadataMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - - const blockchainModuleManager = this.container.resolve('blockchainModuleManager'); - const repositoryModuleManager = this.container.resolve('repositoryModuleManager'); - const tripleStoreService = this.container.resolve('tripleStoreService'); - const serviceAgreementService = this.container.resolve('serviceAgreementService'); - const ualService = this.container.resolve('ualService'); - - const migration = new ServiceAgreementsMetadataMigration( - 'serviceAgreementsMetadataMigration', - this.logger, - this.config, - tripleStoreService, - blockchainModuleManager, - repositoryModuleManager, - serviceAgreementService, - ualService, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } - } - - async executeRemoveAgreementStartEndTimeMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - - const tripleStoreService = this.container.resolve('tripleStoreService'); - - const migration = new RemoveAgreementStartEndTimeMigration( - 'removeAgreementStartEndTimeMigration', - this.logger, - this.config, - tripleStoreService, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } - } - - async executeTripleStoreMetadataMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - const blockchainModuleManager = this.container.resolve('blockchainModuleManager'); - const tripleStoreService = this.container.resolve('tripleStoreService'); - const serviceAgreementService = this.container.resolve('serviceAgreementService'); - const ualService = this.container.resolve('ualService'); - const dataService = this.container.resolve('dataService'); - - const migration = new TripleStoreMetadataMigration( - 'tripleStoreMetadataMigration', - this.logger, - this.config, - tripleStoreService, - blockchainModuleManager, - serviceAgreementService, - ualService, - dataService, - ); - - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } + async startNetworkModule() { + const networkModuleManager = this.container.resolve('networkModuleManager'); + await networkModuleManager.start(); } - async executeRemoveOldEpochCommandsMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - + startTelemetryModule() { + const telemetryModuleManager = this.container.resolve('telemetryModuleManager'); const repositoryModuleManager = this.container.resolve('repositoryModuleManager'); - - const migration = new RemoveOldEpochCommandsMigration( - 'removeOldEpochCommandsMigration', - this.logger, - this.config, - repositoryModuleManager, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } - } - - async executePendingStorageMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - - const migration = new PendingStorageMigration( - 'pendingStorageMigration', - this.logger, - this.config, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } + telemetryModuleManager.listenOnEvents((eventData) => { + repositoryModuleManager.createEventRecord( + eventData.operationId, + eventData.lastEvent, + eventData.timestamp, + eventData.value1, + eventData.value2, + eventData.value3, + ); + }); } async initializeShardingTableService() { @@ -459,22 +334,6 @@ class OTNode { } } - async initializeTelemetryInjectionService() { - if (this.config.telemetry.enabled) { - try { - const telemetryHubModuleManager = this.container.resolve( - 'telemetryInjectionService', - ); - telemetryHubModuleManager.initialize(); - this.logger.info('Telemetry Injection Service initialized successfully'); - } catch (e) { - this.logger.error( - `Telemetry hub module initialization failed. Error message: ${e.message}`, - ); - } - } - } - async removeUpdateFile() { const updateFilePath = this.fileService.getUpdateFilePath(); await this.fileService.removeFile(updateFilePath).catch((error) => { @@ -498,26 +357,6 @@ class OTNode { this.logger.info('Stopping node...'); process.exit(code); } - - async executeMarkOldBlockchainEventsAsProcessedMigration() { - if ( - process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || - process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST - ) - return; - - const repositoryModuleManager = this.container.resolve('repositoryModuleManager'); - - const migration = new MarkOldBlockchainEventsAsProcessedMigration( - 'markOldBlockchainEventsAsProcessedMigration', - this.logger, - this.config, - repositoryModuleManager, - ); - if (!(await migration.migrationAlreadyExecuted())) { - await migration.migrate(); - } - } } export default OTNode; diff --git a/package-lock.json b/package-lock.json index 175adb0e38..bed34ef0d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "origintrail_node", - "version": "6.0.12", + "version": "6.0.19", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "origintrail_node", - "version": "6.0.12", + "version": "6.0.19", "license": "ISC", "dependencies": { "@comunica/query-sparql": "^2.4.3", @@ -54,7 +54,7 @@ "pino-pretty": "^9.1.0", "rc": "^1.2.8", "rolling-rate-limiter": "^0.2.13", - "semver": "^7.3.7", + "semver": "^7.5.2", "sequelize": "^6.29.0", "timeout-abort-controller": "^3.0.0", "toobusy-js": "^0.5.1", @@ -2707,6 +2707,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@cucumber/cucumber/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@cucumber/cucumber/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@cucumber/cucumber/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@cucumber/gherkin": { "version": "26.0.3", "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-26.0.3.tgz", @@ -3629,6 +3662,14 @@ "@ethersproject/strings": "^5.7.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -15569,9 +15610,9 @@ "dev": true }, "node_modules/protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -16553,9 +16594,9 @@ "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -18235,14 +18276,14 @@ } }, "node_modules/undici": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", - "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", "dependencies": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" }, "engines": { - "node": ">=12.18" + "node": ">=14.0" } }, "node_modules/universalify": { @@ -21869,6 +21910,30 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -22449,6 +22514,11 @@ "@ethersproject/strings": "^5.7.0" } }, + "@fastify/busboy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", + "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==" + }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -31816,9 +31886,9 @@ "dev": true }, "protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -32600,9 +32670,9 @@ "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "requires": { "lru-cache": "^6.0.0" }, @@ -33908,11 +33978,11 @@ } }, "undici": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", - "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", "requires": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" } }, "universalify": { diff --git a/package.json b/package.json index 661d967a8a..3a827ac179 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "origintrail_node", - "version": "6.0.13", + "version": "6.0.19", "description": "OTNode V6", "main": "index.js", "type": "module", @@ -104,7 +104,7 @@ "pino-pretty": "^9.1.0", "rc": "^1.2.8", "rolling-rate-limiter": "^0.2.13", - "semver": "^7.3.7", + "semver": "^7.5.2", "sequelize": "^6.29.0", "timeout-abort-controller": "^3.0.0", "toobusy-js": "^0.5.1", diff --git a/postman/DKGv6.postman_collection.json b/postman/DKGv6.postman_collection.json deleted file mode 100644 index 0b358e7617..0000000000 --- a/postman/DKGv6.postman_collection.json +++ /dev/null @@ -1,620 +0,0 @@ -{ - "info": { - "_postman_id": "de092a3d-311c-4c22-9fdb-1f1b777c8bbb", - "name": "DKGv6", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Asset API", - "item": [ - { - "name": "Provision", - "request": { - "auth": { - "type": "noauth" - }, - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "file", - "type": "file", - "src": "/Users/nikolatodorovic/v6/ot-node/demo-data/Feynman.json" - }, - { - "key": "keywords", - "value": "[\"Feynman\",\"Physics\", \"Scientist\"]", - "type": "text" - }, - { - "key": "visibility", - "value": "public", - "type": "text" - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/provision", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "provision" - ] - } - }, - "response": [] - }, - { - "name": "Provision Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/provision/result/7f3c1fef-2588-45e6-b6f6-72f115da6553", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "provision", - "result", - "7f3c1fef-2588-45e6-b6f6-72f115da6553" - ] - } - }, - "response": [] - }, - { - "name": "Update", - "request": { - "auth": { - "type": "noauth" - }, - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "file", - "type": "file", - "src": "/Users/nikolatodorovic/v6/ot-node/demo-data/Feynman.json" - }, - { - "key": "keywords", - "value": "[\"Feynman\",\"Physics\", \"Scientist\"]", - "type": "text" - }, - { - "key": "visibility", - "value": "public", - "type": "text" - }, - { - "key": "ual", - "value": "c37c86b59ba64ab269850860621b634feaab9f500a73ef5620000b8b55dcb29a", - "type": "text" - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/update", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "update" - ] - } - }, - "response": [] - }, - { - "name": "Update Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/update/result/36f9c131-130f-4d41-86e4-7cc6781bb51c", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "update", - "result", - "36f9c131-130f-4d41-86e4-7cc6781bb51c" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Low level API", - "item": [ - { - "name": "Publish", - "request": { - "auth": { - "type": "noauth" - }, - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "file", - "type": "file", - "src": "/Users/nikolatodorovic/v6/ot-node/demo-data/Galileo.json" - }, - { - "key": "keywords", - "value": "[\"Galileo\",\"Scientist\", \"Astronomer\"]", - "type": "text" - }, - { - "key": "visibility", - "value": "public", - "type": "text" - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/publish", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "publish" - ] - } - }, - "response": [] - }, - { - "name": "Publish Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/publish/result/c6c3b9af-0f3c-4324-b5bf-0181d49baa04", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "publish", - "result", - "c6c3b9af-0f3c-4324-b5bf-0181d49baa04" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Resolve", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/resolve?ids=c37c86b59ba64ab269850860621b634feaab9f500a73ef5620000b8b55dcb29a&load=true", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "resolve" - ], - "query": [ - { - "key": "ids", - "value": "c37c86b59ba64ab269850860621b634feaab9f500a73ef5620000b8b55dcb29a" - }, - { - "key": "load", - "value": "true" - } - ] - } - }, - "response": [] - }, - { - "name": "Resolve Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/resolve/result/22419c1a-d41d-4235-9849-e7e1a22edf4f", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "resolve", - "result", - "22419c1a-d41d-4235-9849-e7e1a22edf4f" - ] - } - }, - "response": [] - }, - { - "name": "Assertions Search", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "topic", - "value": "blazard1", - "type": "text", - "disabled": true - }, - { - "key": "limit", - "value": "100", - "type": "text", - "disabled": true - }, - { - "key": "offset", - "value": "0", - "type": "text", - "disabled": true - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/assertions:search?query=scientist", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "assertions:search" - ], - "query": [ - { - "key": "query", - "value": "scientist" - }, - { - "key": "prefix", - "value": "true", - "disabled": true - }, - { - "key": "limit", - "value": "20", - "disabled": true - } - ] - } - }, - "response": [] - }, - { - "name": "Assertions Search Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/assertions:search/result/ccf90eba-4a45-4c47-81e0-1a2e1e679f70", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "assertions:search", - "result", - "ccf90eba-4a45-4c47-81e0-1a2e1e679f70" - ] - } - }, - "response": [] - }, - { - "name": "Search", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "topic", - "value": "blazard1", - "type": "text", - "disabled": true - }, - { - "key": "limit", - "value": "100", - "type": "text", - "disabled": true - }, - { - "key": "offset", - "value": "0", - "type": "text", - "disabled": true - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/entities:search?query=feynman", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "entities:search" - ], - "query": [ - { - "key": "prefix", - "value": "true", - "disabled": true - }, - { - "key": "ids", - "value": "", - "disabled": true - }, - { - "key": "types", - "value": "gs1-epcis", - "disabled": true - }, - { - "key": "limit", - "value": "20", - "disabled": true - }, - { - "key": "issuers", - "value": null, - "disabled": true - }, - { - "key": "query", - "value": "feynman" - } - ] - } - }, - "response": [] - }, - { - "name": "Search Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/entities:search/result/b18a819d-d546-4bc2-95c1-242d78c094e7", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "entities:search", - "result", - "b18a819d-d546-4bc2-95c1-242d78c094e7" - ] - } - }, - "response": [] - }, - { - "name": "Query", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "query", - "value": "PREFIX schema: \nCONSTRUCT { ?s schema:name \"Richard Feynman\" }\nWHERE {\n GRAPH ?g { \n ?s schema:name \"Richard Feynman\" .\n }\n}", - "type": "text" - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/query?type=construct", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "query" - ], - "query": [ - { - "key": "type", - "value": "construct" - } - ] - } - }, - "response": [] - }, - { - "name": "Query Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/query/result/d3480867-d5f7-4f10-9686-8c658c102dcf", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "query", - "result", - "d3480867-d5f7-4f10-9686-8c658c102dcf" - ] - } - }, - "response": [] - }, - { - "name": "Proofs", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "nquads", - "value": "[ \"_:t1253 \\\"Richard Feynman\\\" .\"\n]", - "type": "text" - } - ] - }, - "url": { - "raw": "{{HOST}}:8900/proofs:get", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "proofs:get" - ] - } - }, - "response": [] - }, - { - "name": "Proofs Result", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/proofs:get/result/72d7c0b3-a41e-4f90-91d5-082579f25b65", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "proofs:get", - "result", - "72d7c0b3-a41e-4f90-91d5-082579f25b65" - ] - } - }, - "response": [] - }, - { - "name": "Info", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "formdata", - "formdata": [] - }, - "url": { - "raw": "{{HOST}}:8900/info", - "host": [ - "{{HOST}}" - ], - "port": "8900", - "path": [ - "info" - ] - } - }, - "response": [] - } - ] -} \ No newline at end of file diff --git a/src/commands/command-executor.js b/src/commands/command-executor.js index e62e042acb..9f2a85933a 100644 --- a/src/commands/command-executor.js +++ b/src/commands/command-executor.js @@ -16,7 +16,6 @@ class CommandExecutor { constructor(ctx) { this.logger = ctx.logger; this.commandResolver = ctx.commandResolver; - this.started = false; this.repositoryModuleManager = ctx.repositoryModuleManager; this.verboseLoggingEnabled = ctx.config.commandExecutorVerboseLoggingEnabled; @@ -39,8 +38,8 @@ class CommandExecutor { * Initialize executor * @returns {Promise} */ - async init() { - await Promise.all(PERMANENT_COMMANDS.map((command) => this._startDefaultCommand(command))); + async addDefaultCommands() { + await Promise.all(PERMANENT_COMMANDS.map((command) => this._addDefaultCommand(command))); if (this.verboseLoggingEnabled) { this.logger.trace('Command executor has been initialized...'); @@ -48,14 +47,23 @@ class CommandExecutor { } /** - * Starts the command executor - * @return {Promise} + * Resumes the command executor queue + */ + resumeQueue() { + if (this.verboseLoggingEnabled) { + this.logger.trace('Command executor queue has been resumed...'); + } + this.queue.resume(); + } + + /** + * Pause the command executor queue */ - async start() { - this.started = true; + pauseQueue() { if (this.verboseLoggingEnabled) { - this.logger.trace('Command executor has been started...'); + this.logger.trace('Command executor queue has been paused...'); } + this.queue.pause(); } /** @@ -224,7 +232,7 @@ class CommandExecutor { * @return {Promise} * @private */ - async _startDefaultCommand(name) { + async _addDefaultCommand(name) { await this._delete(name); const handler = this.commandResolver.resolve(name); if (!handler) { @@ -398,7 +406,7 @@ class CommandExecutor { * Replays pending commands from the database * @returns {Promise} */ - async replay() { + async replayOldCommands() { this.logger.info('Replay pending/started commands from the database...'); const pendingCommands = await this.repositoryModuleManager.getCommandsWithStatus( [COMMAND_STATUS.PENDING, COMMAND_STATUS.STARTED, COMMAND_STATUS.REPEATING], diff --git a/src/commands/common/send-telemetry-command.js b/src/commands/common/send-telemetry-command.js index 03fa2ff128..ada1aab635 100644 --- a/src/commands/common/send-telemetry-command.js +++ b/src/commands/common/send-telemetry-command.js @@ -1,4 +1,3 @@ -import axios from 'axios'; import { createRequire } from 'module'; import Command from '../command.js'; import { SEND_TELEMETRY_COMMAND_FREQUENCY_MINUTES } from '../../constants/constants.js'; @@ -11,9 +10,10 @@ class SendTelemetryCommand extends Command { super(ctx); this.logger = ctx.logger; this.config = ctx.config; - this.telemetryInjectionService = ctx.telemetryInjectionService; this.networkModuleManager = ctx.networkModuleManager; this.blockchainModuleManager = ctx.blockchainModuleManager; + this.repositoryModuleManager = ctx.repositoryModuleManager; + this.telemetryModuleManager = ctx.telemetryModuleManager; } /** @@ -21,35 +21,31 @@ class SendTelemetryCommand extends Command { * @param command */ async execute() { - if (!this.config.telemetry.enabled || !this.config.telemetry.sendTelemetryData) { + if ( + !this.config.modules.telemetry.enabled || + !this.telemetryModuleManager.getModuleConfiguration().sendTelemetryData + ) { return Command.empty(); } + try { - const events = await this.telemetryInjectionService.getUnpublishedEvents(); - const signalingMessage = { - nodeData: { - version: pjson.version, - identity: this.networkModuleManager.getPeerId().toB58String(), - hostname: this.config.hostname, - operational_wallet: this.blockchainModuleManager.getPublicKey(), - management_wallet: this.blockchainModuleManager.getManagementKey(), - triple_store: this.config.modules.tripleStore.defaultImplementation, - auto_update_enabled: this.config.modules.autoUpdater.enabled, - multiaddresses: this.networkModuleManager.getMultiaddrs(), - }, - events: events || [], - }; - const config = { - method: 'post', - url: this.config.telemetry.signalingServerUrl, - headers: { - 'Content-Type': 'application/json', - }, - data: JSON.stringify(signalingMessage), + const events = (await this.getUnpublishedEvents()) || []; + const nodeData = { + version: pjson.version, + identity: this.networkModuleManager.getPeerId().toB58String(), + hostname: this.config.hostname, + operational_wallet: this.blockchainModuleManager.getPublicKey(), + management_wallet: this.blockchainModuleManager.getManagementKey(), + triple_store: this.config.modules.tripleStore.defaultImplementation, + auto_update_enabled: this.config.modules.autoUpdater.enabled, + multiaddresses: this.networkModuleManager.getMultiaddrs(), }; - const response = await axios(config); - if (response.status === 200 && events?.length > 0) { - await this.telemetryInjectionService.removePublishedEvents(events); + const isDataSuccessfullySent = await this.telemetryModuleManager.sendTelemetryData( + nodeData, + events, + ); + if (isDataSuccessfullySent && events?.length > 0) { + await this.removePublishedEvents(events); } } catch (e) { await this.handleError(e); @@ -83,6 +79,16 @@ class SendTelemetryCommand extends Command { Object.assign(command, map); return command; } + + async getUnpublishedEvents() { + return this.repositoryModuleManager.getUnpublishedEvents(); + } + + async removePublishedEvents(events) { + const ids = events.map((event) => event.id); + + await this.repositoryModuleManager.destroyEvents(ids); + } } export default SendTelemetryCommand; diff --git a/src/commands/common/validate-asset-command.js b/src/commands/common/validate-asset-command.js index 458396d630..317a45cdb6 100644 --- a/src/commands/common/validate-asset-command.js +++ b/src/commands/common/validate-asset-command.js @@ -1,5 +1,10 @@ import Command from '../command.js'; -import { ERROR_TYPE, OPERATION_ID_STATUS, LOCAL_STORE_TYPES } from '../../constants/constants.js'; +import { + ERROR_TYPE, + OPERATION_ID_STATUS, + LOCAL_STORE_TYPES, + ZERO_BYTES32, +} from '../../constants/constants.js'; class ValidateAssetCommand extends Command { constructor(ctx) { @@ -43,7 +48,7 @@ class ValidateAssetCommand extends Command { tokenId, ); } - if (!blockchainAssertionId) { + if (!blockchainAssertionId || blockchainAssertionId === ZERO_BYTES32) { return Command.retry(); } const cachedData = await this.operationIdService.getCachedOperationIdData(operationId); diff --git a/src/commands/local-store/local-store-command.js b/src/commands/local-store/local-store-command.js index 8719f8d322..5bf84abc00 100644 --- a/src/commands/local-store/local-store-command.js +++ b/src/commands/local-store/local-store-command.js @@ -93,8 +93,11 @@ class LocalStoreCommand extends Command { await this.commandExecutor.add({ name: 'deletePendingStateCommand', sequence: [], - delay: updateCommitWindowDuration * 1000, - data: { ...command.data, repository: PENDING_STORAGE_REPOSITORIES.PRIVATE }, + delay: (updateCommitWindowDuration + 60) * 1000, + data: { + ...command.data, + assertionId: cachedData.public.assertionId, + }, transactional: false, }); } diff --git a/src/commands/protocols/common/epoch-check-command.js b/src/commands/protocols/common/epoch-check-command.js index 3d674f498b..330a700f09 100644 --- a/src/commands/protocols/common/epoch-check-command.js +++ b/src/commands/protocols/common/epoch-check-command.js @@ -5,6 +5,7 @@ import { COMMAND_RETRIES, TRANSACTION_CONFIRMATIONS, OPERATION_ID_STATUS, + ERROR_TYPE, } from '../../../constants/constants.js'; class EpochCheckCommand extends Command { @@ -16,6 +17,8 @@ class EpochCheckCommand extends Command { this.shardingTableService = ctx.shardingTableService; this.blockchainModuleManager = ctx.blockchainModuleManager; this.serviceAgreementService = ctx.serviceAgreementService; + + this.errorType = ERROR_TYPE.COMMIT_PROOF.EPOCH_CHECK_ERROR; } async execute(command) { @@ -99,43 +102,56 @@ class EpochCheckCommand extends Command { for (const serviceAgreement of eligibleAgreementForSubmitCommit) { if (scheduleSubmitCommitCommands.length >= maxTransactions) break; - const rank = await this.calculateRank( - blockchain, - serviceAgreement.keyword, - serviceAgreement.hashFunctionId, - r2, - ); - - updateServiceAgreementsLastCommitEpoch.push( - this.repositoryModuleManager.updateServiceAgreementLastCommitEpoch( - serviceAgreement.agreementId, - serviceAgreement.currentEpoch, - ), - ); + try { + const rank = await this.calculateRank( + blockchain, + serviceAgreement.keyword, + serviceAgreement.hashFunctionId, + r2, + ); - if (rank == null) { - this.logger.trace( - `Node not in R2: ${r2} for agreement id: ${serviceAgreement.agreementId}. Skipping scheduling submit commit command.`, + updateServiceAgreementsLastCommitEpoch.push( + this.repositoryModuleManager.updateServiceAgreementLastCommitEpoch( + serviceAgreement.agreementId, + serviceAgreement.currentEpoch, + ), ); - continue; - } - if (rank >= r0) { + if (rank == null) { + this.logger.trace( + `Node not in R2: ${r2} for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Skipping scheduling submitCommitCommand.`, + ); + continue; + } + + if (rank >= r0) { + this.logger.trace( + `Calculated rank: ${ + rank + 1 + }. Node not in R0: ${r0} for the Service Agreement with the ID: ${ + serviceAgreement.agreementId + }. Skipping scheduling submitCommitCommand.`, + ); + continue; + } + this.logger.trace( - `Calculated rank: ${rank + 1}. Node not in R0: ${r0} for agreement id: ${ + `Calculated rank: ${ + rank + 1 + }. Node in R0: ${r0} for the Service Agreement with the ID: ${ serviceAgreement.agreementId - }. Skipping scheduling submit commit command.`, + }. Scheduling submitCommitCommand.`, + ); + + scheduleSubmitCommitCommands.push( + this.scheduleSubmitCommitCommand(serviceAgreement), + ); + } catch (error) { + this.logger.warn( + `Failed to schedule submitCommitCommand for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Error message: ${error.message}.`, ); continue; } - - this.logger.trace( - `Calculated rank: ${rank + 1}. Node in R0: ${r0} for agreement id: ${ - serviceAgreement.agreementId - }. Scheduling submit commit command.`, - ); - - scheduleSubmitCommitCommands.push(this.scheduleSubmitCommitCommand(serviceAgreement)); } await Promise.all([ ...scheduleSubmitCommitCommands, @@ -161,32 +177,39 @@ class EpochCheckCommand extends Command { for (const serviceAgreement of eligibleAgreementsForSubmitProofs) { if (scheduleSubmitProofCommands.length >= maxTransactions) break; - const eligibleForReward = await this.isEligibleForRewards( - blockchain, - serviceAgreement.agreementId, - serviceAgreement.currentEpoch, - serviceAgreement.stateIndex, - r0, - ); - if (eligibleForReward) { - this.logger.trace( - `Node is eligible for rewards for agreement id: ${serviceAgreement.agreementId}. Scheduling submit proof command.`, + try { + const eligibleForReward = await this.isEligibleForRewards( + blockchain, + serviceAgreement.agreementId, + serviceAgreement.currentEpoch, + serviceAgreement.stateIndex, + r0, ); - - scheduleSubmitProofCommands.push( - this.scheduleSubmitProofsCommand(serviceAgreement), + if (eligibleForReward) { + this.logger.trace( + `Node is eligible for rewards for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Scheduling submitProofsCommand.`, + ); + + scheduleSubmitProofCommands.push( + this.scheduleSubmitProofsCommand(serviceAgreement), + ); + } else { + this.logger.trace( + `Node is not eligible for rewards for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Skipping scheduling submitProofsCommand.`, + ); + } + updateServiceAgreementsLastProofEpoch.push( + this.repositoryModuleManager.updateServiceAgreementLastProofEpoch( + serviceAgreement.agreementId, + serviceAgreement.currentEpoch, + ), ); - } else { - this.logger.trace( - `Node is not eligible for rewards for agreement id: ${serviceAgreement.agreementId}. Skipping scheduling submit proof command.`, + } catch (error) { + this.logger.warn( + `Failed to schedule submitProofsCommand for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Error message: ${error.message}.`, ); + continue; } - updateServiceAgreementsLastProofEpoch.push( - this.repositoryModuleManager.updateServiceAgreementLastProofEpoch( - serviceAgreement.agreementId, - serviceAgreement.currentEpoch, - ), - ); } await Promise.all([ ...scheduleSubmitProofCommands, @@ -326,7 +349,7 @@ class EpochCheckCommand extends Command { * @param error */ async recover(command, error) { - this.logger.warn(`Failed to execute ${command.name}: error: ${error.message}`); + this.logger.warn(`Failed to execute ${command.name}; Error: ${error.message}`); return Command.repeat(); } diff --git a/src/commands/protocols/common/submit-commit-command.js b/src/commands/protocols/common/submit-commit-command.js index 7c9cfba13a..e8534b0ee2 100644 --- a/src/commands/protocols/common/submit-commit-command.js +++ b/src/commands/protocols/common/submit-commit-command.js @@ -49,8 +49,14 @@ class SubmitCommitCommand extends Command { stateIndex, ); if (alreadySubmitted) { - this.logger.trace( - `Commit already submitted for blockchain: ${blockchain} agreement id: ${agreementId}, epoch: ${epoch}, state index: ${stateIndex}`, + const errorMessage = `Commit already submitted for blockchain: ${blockchain} agreement id: ${agreementId}, epoch: ${epoch}, state index: ${stateIndex}`; + this.logger.trace(errorMessage); + + this.operationIdService.emitChangeEvent( + OPERATION_ID_STATUS.COMMIT_PROOF.SUBMIT_COMMIT_END, + operationId, + agreementId, + epoch, ); return Command.empty(); } @@ -65,7 +71,10 @@ class SubmitCommitCommand extends Command { epoch, stateIndex, (result) => { - if (result?.error) { + if ( + result?.error && + !result.error.message.includes('NodeAlreadySubmittedCommit') + ) { reject(result.error); } resolve(); diff --git a/src/commands/protocols/common/submit-proofs-command.js b/src/commands/protocols/common/submit-proofs-command.js index 8348480f84..699f7e2cb3 100644 --- a/src/commands/protocols/common/submit-proofs-command.js +++ b/src/commands/protocols/common/submit-proofs-command.js @@ -66,7 +66,10 @@ class SubmitProofsCommand extends Command { ); if (!assertion.length) { - this.logger.trace(`Assertion with id: ${assertionId} not found in triple store.`); + const errorMessage = `Assertion with id: ${assertionId} not found in triple store.`; + this.logger.trace(errorMessage); + + await this.handleError(operationId, errorMessage, this.errorType, true); return Command.empty(); } @@ -97,8 +100,14 @@ class SubmitProofsCommand extends Command { stateIndex, ); if (alreadySubmitted) { - this.logger.trace( - `Proofs already submitted for blockchain: ${blockchain} agreement id: ${agreementId}, epoch: ${epoch}, state index: ${stateIndex}`, + const errorMessage = `Proofs already submitted for blockchain: ${blockchain} agreement id: ${agreementId}, epoch: ${epoch}, state index: ${stateIndex}`; + this.logger.trace(errorMessage); + + this.operationIdService.emitChangeEvent( + OPERATION_ID_STATUS.COMMIT_PROOF.SUBMIT_PROOFS_END, + operationId, + agreementId, + epoch, ); return Command.empty(); } @@ -115,7 +124,7 @@ class SubmitProofsCommand extends Command { leaf, stateIndex, (result) => { - if (result?.error) { + if (result?.error && !result.error.message.includes('NodeAlreadyRewarded')) { reject(result.error); } resolve(); diff --git a/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-init-command.js b/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-init-command.js index e8bcd7aee4..8dbef0a104 100644 --- a/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-init-command.js +++ b/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-init-command.js @@ -42,22 +42,24 @@ class HandleGetInitCommand extends HandleProtocolMessageCommand { blockchain, contract, tokenId, + assertionId, ); } - for (const repository of [ - TRIPLE_STORE_REPOSITORIES.PUBLIC_CURRENT, - TRIPLE_STORE_REPOSITORIES.PUBLIC_HISTORY, - ]) { - if (assertionExists) { - break; + if (!assertionExists) { + for (const repository of [ + TRIPLE_STORE_REPOSITORIES.PUBLIC_CURRENT, + TRIPLE_STORE_REPOSITORIES.PUBLIC_HISTORY, + ]) { + // eslint-disable-next-line no-await-in-loop + assertionExists = await this.tripleStoreService.assertionExists( + repository, + assertionId, + ); + if (assertionExists) { + break; + } } - - // eslint-disable-next-line no-await-in-loop - assertionExists = await this.tripleStoreService.assertionExists( - repository, - assertionId, - ); } await this.operationIdService.updateOperationIdStatus( diff --git a/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js b/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js index 55adc3989e..576dbe8a5a 100644 --- a/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js +++ b/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js @@ -26,6 +26,7 @@ class HandleGetRequestCommand extends HandleProtocolMessageCommand { OPERATION_ID_STATUS.GET.GET_REMOTE_START, ); + let nquads; if ( state !== GET_STATES.FINALIZED && blockchain != null && @@ -37,26 +38,24 @@ class HandleGetRequestCommand extends HandleProtocolMessageCommand { blockchain, contract, tokenId, + assertionId, operationId, ); if (cachedAssertion?.public?.assertion?.length) { - return { - messageType: NETWORK_MESSAGE_TYPES.RESPONSES.ACK, - messageData: { nquads: cachedAssertion.public.assertion }, - }; + nquads = cachedAssertion.public.assertion; } } - let nquads; - for (const repository of [ - TRIPLE_STORE_REPOSITORIES.PUBLIC_CURRENT, - TRIPLE_STORE_REPOSITORIES.PUBLIC_HISTORY, - ]) { - // eslint-disable-next-line no-await-in-loop - nquads = await this.tripleStoreService.getAssertion(repository, assertionId); - - if (nquads.length) { - break; + if (!nquads?.length) { + for (const repository of [ + TRIPLE_STORE_REPOSITORIES.PUBLIC_CURRENT, + TRIPLE_STORE_REPOSITORIES.PUBLIC_HISTORY, + ]) { + // eslint-disable-next-line no-await-in-loop + nquads = await this.tripleStoreService.getAssertion(repository, assertionId); + if (nquads.length) { + break; + } } } diff --git a/src/commands/protocols/get/sender/get-assertion-id-command.js b/src/commands/protocols/get/sender/get-assertion-id-command.js index b4af9d93d3..cf40c8d681 100644 --- a/src/commands/protocols/get/sender/get-assertion-id-command.js +++ b/src/commands/protocols/get/sender/get-assertion-id-command.js @@ -75,10 +75,7 @@ class GetAssertionIdCommand extends Command { } } - return this.continueSequence( - { ...command.data, state: assertionId, assertionId }, - command.sequence, - ); + return this.continueSequence({ ...command.data, state, assertionId }, command.sequence); } async handleError(operationId, errorMessage, errorType) { diff --git a/src/commands/protocols/get/sender/local-get-command.js b/src/commands/protocols/get/sender/local-get-command.js index f9d09cf0f8..8d64f8186e 100644 --- a/src/commands/protocols/get/sender/local-get-command.js +++ b/src/commands/protocols/get/sender/local-get-command.js @@ -2,6 +2,7 @@ import Command from '../../../command.js'; import { OPERATION_ID_STATUS, ERROR_TYPE, + GET_STATES, TRIPLE_STORE_REPOSITORIES, PENDING_STORAGE_REPOSITORIES, } from '../../../../constants/constants.js'; @@ -24,42 +25,50 @@ class LocalGetCommand extends Command { * @param command */ async execute(command) { - const { operationId, blockchain, contract, tokenId, state } = command.data; + const { operationId, blockchain, contract, tokenId, assertionId, state } = command.data; await this.operationIdService.updateOperationIdStatus( operationId, OPERATION_ID_STATUS.GET.GET_LOCAL_START, ); const response = {}; - for (const repository of [ - PENDING_STORAGE_REPOSITORIES.PRIVATE, - PENDING_STORAGE_REPOSITORIES.PUBLIC, - ]) { - // eslint-disable-next-line no-await-in-loop - const stateIsPending = await this.pendingStorageService.assetHasPendingState( - repository, - blockchain, - contract, - tokenId, - state, - ); - - if (stateIsPending) { + if ( + state !== GET_STATES.FINALIZED && + blockchain != null && + contract != null && + tokenId != null + ) { + for (const repository of [ + PENDING_STORAGE_REPOSITORIES.PRIVATE, + PENDING_STORAGE_REPOSITORIES.PUBLIC, + ]) { // eslint-disable-next-line no-await-in-loop - const cachedAssertion = await this.pendingStorageService.getCachedAssertion( + const stateIsPending = await this.pendingStorageService.assetHasPendingState( repository, blockchain, contract, tokenId, - operationId, + assertionId, ); - if (cachedAssertion?.public?.assertion?.length) { - response.assertion = cachedAssertion.public.assertion; - if (cachedAssertion?.private?.assertion?.length) { - response.privateAssertion = cachedAssertion.private.assertion; + if (stateIsPending) { + // eslint-disable-next-line no-await-in-loop + const cachedAssertion = await this.pendingStorageService.getCachedAssertion( + repository, + blockchain, + contract, + tokenId, + assertionId, + operationId, + ); + + if (cachedAssertion?.public?.assertion?.length) { + response.assertion = cachedAssertion.public.assertion; + if (cachedAssertion?.private?.assertion?.length) { + response.privateAssertion = cachedAssertion.private.assertion; + } + break; } - break; } } } @@ -72,7 +81,10 @@ class LocalGetCommand extends Command { TRIPLE_STORE_REPOSITORIES.PUBLIC_HISTORY, ]) { // eslint-disable-next-line no-await-in-loop - response.assertion = await this.tripleStoreService.getAssertion(repository, state); + response.assertion = await this.tripleStoreService.getAssertion( + repository, + assertionId, + ); if (response?.assertion?.length) break; } } diff --git a/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-request-command.js b/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-request-command.js index 0caa031c63..5e82bd6178 100644 --- a/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-request-command.js +++ b/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-request-command.js @@ -83,22 +83,6 @@ class HandleStoreRequestCommand extends HandleProtocolMessageCommand { stateIndex, ); - await this.repositoryModuleManager.updateServiceAgreementRecord( - blockchain, - contract, - tokenId, - agreementId, - agreementData.startTime, - agreementData.epochsNumber, - agreementData.epochLength, - agreementData.scoreFunctionId, - agreementData.proofWindowOffsetPerc, - hashFunctionId, - keyword, - assertionId, - stateIndex, - ); - await this.operationIdService.updateOperationIdStatus( operationId, OPERATION_ID_STATUS.PUBLISH.PUBLISH_LOCAL_STORE_END, diff --git a/src/commands/protocols/update/receiver/delete-pending-state-command.js b/src/commands/protocols/update/receiver/delete-pending-state-command.js index a8b824e674..defa18d8d2 100644 --- a/src/commands/protocols/update/receiver/delete-pending-state-command.js +++ b/src/commands/protocols/update/receiver/delete-pending-state-command.js @@ -1,25 +1,64 @@ import Command from '../../../command.js'; -import { ERROR_TYPE } from '../../../../constants/constants.js'; +import { ERROR_TYPE, PENDING_STORAGE_REPOSITORIES } from '../../../../constants/constants.js'; class DeletePendingStateCommand extends Command { constructor(ctx) { super(ctx); + this.blockchainModuleManager = ctx.blockchainModuleManager; this.pendingStorageService = ctx.pendingStorageService; this.errorType = ERROR_TYPE.UPDATE.UPDATE_DELETE_PENDING_STATE_ERROR; } async execute(command) { - const { blockchain, contract, tokenId, operationId, repository } = command.data; + const { blockchain, contract, tokenId, assertionId, operationId } = command.data; - await this.pendingStorageService.removeCachedAssertion( - repository, + this.logger.trace( + `Started ${command.name} for blockchain: ${blockchain} contract: ${contract}, ` + + `token id: ${tokenId}, assertion id: ${assertionId}`, + ); + + const assetStates = await this.blockchainModuleManager.getAssertionIds( blockchain, contract, tokenId, - operationId, ); + if (assetStates.includes(assertionId)) { + this.logger.trace( + `Not clearing the pending storage as state was finalized and clearing is triggered by StateFinalized event.`, + ); + return Command.empty(); + } + + for (const repository of [ + PENDING_STORAGE_REPOSITORIES.PUBLIC, + PENDING_STORAGE_REPOSITORIES.PRIVATE, + ]) { + // eslint-disable-next-line no-await-in-loop + const pendingStateExists = await this.pendingStorageService.assetHasPendingState( + repository, + blockchain, + contract, + tokenId, + assertionId, + ); + + if (!pendingStateExists) { + continue; + } + + // eslint-disable-next-line no-await-in-loop + await this.pendingStorageService.removeCachedAssertion( + repository, + blockchain, + contract, + tokenId, + assertionId, + operationId, + ); + } + return Command.empty(); } diff --git a/src/commands/protocols/update/receiver/submit-update-commit-command.js b/src/commands/protocols/update/receiver/submit-update-commit-command.js index 7c40eb0f56..bf5289600a 100644 --- a/src/commands/protocols/update/receiver/submit-update-commit-command.js +++ b/src/commands/protocols/update/receiver/submit-update-commit-command.js @@ -108,8 +108,8 @@ class SubmitUpdateCommitCommand extends Command { this.logger.trace( `Scheduled submit update commit transaction for agreement id: ${agreementId} ` + `blockchain: ${blockchain} contract: ${contract}, token id: ${tokenId}, ` + - `keyword: ${keyword}, hash function id: ${hashFunctionId}, operationId ${operationId}` + - `transaction queue length: ${transactionQueueLength}.`, + `keyword: ${keyword}, hash function id: ${hashFunctionId}, operationId ${operationId}. ` + + `Transaction queue length: ${transactionQueueLength}.`, ); return Command.empty(); diff --git a/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js b/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js index 83eff51b71..0429b3c1f3 100644 --- a/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js +++ b/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js @@ -100,8 +100,11 @@ class HandleUpdateRequestCommand extends HandleProtocolMessageCommand { this.commandExecutor.add({ name: 'deletePendingStateCommand', sequence: [], - delay: updateCommitWindowDuration * 1000, - data: { ...commandData, repository: PENDING_STORAGE_REPOSITORIES.PUBLIC }, + delay: (updateCommitWindowDuration + 60) * 1000, + data: { + ...commandData, + assertionId: cachedData.assertionId, + }, transactional: false, }), ); diff --git a/src/constants/constants.js b/src/constants/constants.js index 9c807292ea..ba1d328b3c 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -1,5 +1,13 @@ import { BigNumber } from 'ethers'; +export const WS_RPC_PROVIDER_PRIORITY = 2; + +export const HTTP_RPC_PROVIDER_PRIORITY = 1; + +export const FALLBACK_PROVIDER_QUORUM = 1; + +export const RPC_PROVIDER_STALL_TIMEOUT = 60 * 1000; + export const UINT256_MAX_BN = BigNumber.from(2).pow(256).sub(1); export const UINT32_MAX_BN = BigNumber.from(2).pow(32).sub(1); @@ -8,6 +16,8 @@ export const STAKE_UINT256_MULTIPLIER_BN = UINT256_MAX_BN.div(500000000); export const UINT256_UINT32_DIVISOR_BN = UINT256_MAX_BN.div(UINT32_MAX_BN); +export const ZERO_PREFIX = '0x'; + export const ZERO_BYTES32 = `0x${'0'.repeat(64)}`; export const SCHEMA_CONTEXT = 'http://schema.org/'; @@ -19,7 +29,23 @@ export const COMMIT_BLOCK_DURATION_IN_BLOCKS = 5; export const COMMITS_DELAY_BETWEEN_NODES_IN_BLOCKS = 2; -export const TRANSACTION_POLLING_TIMEOUT_MILLIS = 50 * 1000; +export const TRANSACTION_POLLING_TIMEOUT_MILLIS = 120 * 1000; + +export const SOLIDITY_ERROR_STRING_PREFIX = '0x08c379a0'; + +export const SOLIDITY_PANIC_CODE_PREFIX = '0x4e487b71'; + +export const SOLIDITY_PANIC_REASONS = { + 0x1: 'Assertion error', + 0x11: 'Arithmetic operation underflowed or overflowed outside of an unchecked block', + 0x12: 'Division or modulo division by zero', + 0x21: 'Tried to convert a value into an enum, but the value was too big or negative', + 0x22: 'Incorrectly encoded storage byte array', + 0x31: '.pop() was called on an empty array', + 0x32: 'Array accessed at an out-of-bounds or negative index', + 0x41: 'Too much memory was allocated, or an array was created that is too large', + 0x51: 'Called a zero-initialized variable of internal function type', +}; export const LIBP2P_KEY_DIRECTORY = 'libp2p'; @@ -38,6 +64,7 @@ export const TRIPLE_STORE_CONNECT_RETRY_FREQUENCY = 10; export const MAX_FILE_SIZE = 2621440; export const GET_STATES = { LATEST: 'LATEST', FINALIZED: 'LATEST_FINALIZED' }; + export const BYTES_IN_KILOBYTE = 1024; export const BYTES_IN_MEGABYTE = BYTES_IN_KILOBYTE * BYTES_IN_KILOBYTE; @@ -148,9 +175,9 @@ export const DEFAULT_COMMAND_REPEAT_INTERVAL_IN_MILLS = 5000; // 5 seconds export const DEFAULT_COMMAND_DELAY_IN_MILLS = 60 * 1000; // 60 seconds export const COMMAND_RETRIES = { - SUBMIT_COMMIT: 3, - SUBMIT_UPDATE_COMMIT: 3, - SUBMIT_PROOFS: 3, + SUBMIT_COMMIT: 0, + SUBMIT_UPDATE_COMMIT: 0, + SUBMIT_PROOFS: 0, }; export const WEBSOCKET_PROVIDER_OPTIONS = { @@ -414,6 +441,56 @@ export const ARCHIVE_UPDATE_RESPONSES_FOLDER = 'update_responses'; */ export const COMMAND_QUEUE_PARALLELISM = 100; +/** + * @constant {object} HTTP_API_ROUTES - + * HTTP API Routes with parameters + */ +export const HTTP_API_ROUTES = { + v0: { + publish: { + method: 'post', + path: '/publish', + options: { rateLimit: true }, + }, + update: { + method: 'post', + path: '/update', + options: { rateLimit: true }, + }, + query: { + method: 'post', + path: '/query', + options: {}, + }, + 'local-store': { + method: 'post', + path: '/local-store', + options: {}, + }, + get: { + method: 'post', + path: '/get', + options: { rateLimit: true }, + }, + result: { + method: 'get', + path: '/:operation/:operationId', + options: {}, + }, + info: { + method: 'get', + path: '/info', + options: {}, + }, + 'bid-suggestion': { + method: 'get', + path: '/bid-suggestion', + options: {}, + }, + }, + v1: {}, +}; + /** * @constant {object} NETWORK_PROTOCOLS - * Network protocols @@ -492,12 +569,6 @@ export const CONTRACT_EVENT_FETCH_INTERVALS = { DEVELOPMENT: 4 * 1000, }; -export const FIXED_GAS_LIMIT_METHODS = { - submitCommit: 600000, - submitUpdateCommit: 600000, - sendProof: 500000, -}; - export const BLOCK_TIME_MILLIS = { OTP: 12_000, HARDHAT: 5_000, diff --git a/src/controllers/http-api/base-http-api-controller.js b/src/controllers/http-api/base-http-api-controller.js index fe742fd5a9..3a080b9f5a 100644 --- a/src/controllers/http-api/base-http-api-controller.js +++ b/src/controllers/http-api/base-http-api-controller.js @@ -1,5 +1,6 @@ class BaseController { constructor(ctx) { + this.config = ctx.config; this.logger = ctx.logger; } diff --git a/src/controllers/http-api/http-api-router.js b/src/controllers/http-api/http-api-router.js index 04cc727c7e..cadf110dfd 100644 --- a/src/controllers/http-api/http-api-router.js +++ b/src/controllers/http-api/http-api-router.js @@ -1,89 +1,89 @@ +import stringUtil from '../../service/util/string-util.js'; +import { HTTP_API_ROUTES } from '../../constants/constants.js'; + class HttpApiRouter { constructor(ctx) { - this.config = ctx.config; this.httpClientModuleManager = ctx.httpClientModuleManager; - this.getHttpApiController = ctx.getHttpApiController; - this.publishHttpApiController = ctx.publishHttpApiController; - this.updateHttpApiController = ctx.updateHttpApiController; - this.localStoreHttpApiController = ctx.localStoreHttpApiController; - this.queryHttpApiController = ctx.queryHttpApiController; - this.resultHttpApiController = ctx.resultHttpApiController; - this.infoHttpApiController = ctx.infoHttpApiController; - this.bidSuggestionHttpApiController = ctx.bidSuggestionHttpApiController; + this.apiRoutes = HTTP_API_ROUTES; + this.apiVersions = Object.keys(this.apiRoutes); + + this.routers = {}; + for (const version of this.apiVersions) { + this.routers[version] = this.httpClientModuleManager.createRouterInstance(); + + const operations = Object.keys(this.apiRoutes[version]); + + for (const operation of operations) { + const versionedController = `${stringUtil.toCamelCase( + operation, + )}HttpApiController${stringUtil.capitalize(version)}`; + + this[versionedController] = ctx[versionedController]; + } + } + this.routers.latest = this.httpClientModuleManager.createRouterInstance(); this.jsonSchemaService = ctx.jsonSchemaService; } async initialize() { this.initializeBeforeMiddlewares(); - this.initializeListeners(); + await this.initializeVersionedListeners(); + this.initializeRouters(); this.initializeAfterMiddlewares(); await this.httpClientModuleManager.listen(); } - initializeListeners() { - this.httpClientModuleManager.post( - '/publish', - (req, res) => { - this.publishHttpApiController.handlePublishRequest(req, res); - }, - { rateLimit: true, requestSchema: this.jsonSchemaService.publishSchema() }, - ); - - this.httpClientModuleManager.post( - '/update', - (req, res) => { - this.updateHttpApiController.handleUpdateRequest(req, res); - }, - { rateLimit: true, requestSchema: this.jsonSchemaService.updateSchema() }, - ); - - this.httpClientModuleManager.post( - '/query', - (req, res) => { - this.queryHttpApiController.handleQueryRequest(req, res); - }, - { requestSchema: this.jsonSchemaService.querySchema() }, - ); - - this.httpClientModuleManager.post( - '/local-store', - (req, res) => { - this.localStoreHttpApiController.handleLocalStoreRequest(req, res); - }, - { requestSchema: this.jsonSchemaService.localStoreSchema() }, - ); - - this.httpClientModuleManager.post( - '/get', - (req, res) => { - this.getHttpApiController.handleGetRequest(req, res); - }, - { rateLimit: true, requestSchema: this.jsonSchemaService.getSchema() }, - ); - - this.httpClientModuleManager.get('/:operation/:operationId', (req, res) => { - this.resultHttpApiController.handleOperationResultRequest(req, res); - }); - - this.httpClientModuleManager.get('/info', (req, res) => { - this.infoHttpApiController.handleInfoRequest(req, res); - }); - - this.httpClientModuleManager.get( - '/bid-suggestion', - (req, res) => { - this.bidSuggestionHttpApiController.handleBidSuggestionRequest(req, res); - }, - { requestSchema: this.jsonSchemaService.bidSuggestionSchema() }, - ); - } - initializeBeforeMiddlewares() { this.httpClientModuleManager.initializeBeforeMiddlewares(); } + async initializeVersionedListeners() { + const descendingOrderedVersions = this.apiVersions.sort((a, b) => b.localeCompare(a)); + const mountedLatestRoutes = new Set(); + + for (const version of descendingOrderedVersions) { + for (const [name, route] of Object.entries(this.apiRoutes[version])) { + const { method, path, options } = route; + const camelRouteName = stringUtil.toCamelCase(name); + const controller = `${camelRouteName}HttpApiController${stringUtil.capitalize( + version, + )}`; + const schema = `${camelRouteName}Schema`; + + if ( + schema in this.jsonSchemaService && + typeof this.jsonSchemaService[schema] === 'function' + ) { + // eslint-disable-next-line no-await-in-loop + options.requestSchema = await this.jsonSchemaService[schema](version); + } + + const middlewares = this.httpClientModuleManager.selectMiddlewares(options); + const callback = (req, res) => { + this[controller].handleRequest(req, res); + }; + + this.routers[version][method](path, ...middlewares, callback); + + if (!mountedLatestRoutes.has(route.name)) { + this.routers.latest[method](path, ...middlewares, callback); + mountedLatestRoutes.add(route.name); + } + } + } + } + + initializeRouters() { + for (const version of this.apiVersions) { + this.httpClientModuleManager.use(`/${version}`, this.routers[version]); + } + + this.httpClientModuleManager.use('/latest', this.routers.latest); + this.httpClientModuleManager.use('/', this.routers.v0); + } + initializeAfterMiddlewares() { this.httpClientModuleManager.initializeAfterMiddlewares(); } diff --git a/src/controllers/http-api/bid-suggestion-http-api-controller.js b/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js similarity index 94% rename from src/controllers/http-api/bid-suggestion-http-api-controller.js rename to src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js index 2bf0967b56..e41932c32b 100644 --- a/src/controllers/http-api/bid-suggestion-http-api-controller.js +++ b/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js @@ -1,4 +1,4 @@ -import BaseController from './base-http-api-controller.js'; +import BaseController from '../base-http-api-controller.js'; class BidSuggestionController extends BaseController { constructor(ctx) { @@ -8,7 +8,7 @@ class BidSuggestionController extends BaseController { this.shardingTableService = ctx.shardingTableService; } - async handleBidSuggestionRequest(req, res) { + async handleRequest(req, res) { if ((await this.repositoryModuleManager.getPeersCount(req.query.blockchain)) === 0) this.returnResponse(res, 400, { code: 400, diff --git a/src/controllers/http-api/get-http-api-controller.js b/src/controllers/http-api/v0/get-http-api-controller-v0.js similarity index 91% rename from src/controllers/http-api/get-http-api-controller.js rename to src/controllers/http-api/v0/get-http-api-controller-v0.js index 8855bb0a99..f743fb48a6 100644 --- a/src/controllers/http-api/get-http-api-controller.js +++ b/src/controllers/http-api/v0/get-http-api-controller-v0.js @@ -4,8 +4,8 @@ import { CONTENT_ASSET_HASH_FUNCTION_ID, DEFAULT_GET_STATE, ERROR_TYPE, -} from '../../constants/constants.js'; -import BaseController from './base-http-api-controller.js'; +} from '../../../constants/constants.js'; +import BaseController from '../base-http-api-controller.js'; class GetController extends BaseController { constructor(ctx) { @@ -18,7 +18,7 @@ class GetController extends BaseController { this.validationService = ctx.validationService; } - async handleGetRequest(req, res) { + async handleRequest(req, res) { const operationId = await this.operationIdService.generateOperationId( OPERATION_ID_STATUS.GET.GET_START, ); @@ -87,9 +87,7 @@ class GetController extends BaseController { OPERATION_ID_STATUS.GET.GET_INIT_END, ); } catch (error) { - this.logger.error( - `Error while initializing get data: ${error.message}. ${error.stack}`, - ); + this.logger.error(`Error while initializing get data: ${error.message}.`); await this.operationService.markOperationAsFailed( operationId, diff --git a/src/controllers/http-api/info-http-api-controller.js b/src/controllers/http-api/v0/info-http-api-controller-v0.js similarity index 62% rename from src/controllers/http-api/info-http-api-controller.js rename to src/controllers/http-api/v0/info-http-api-controller-v0.js index 03ee42ebd5..61dbb514ed 100644 --- a/src/controllers/http-api/info-http-api-controller.js +++ b/src/controllers/http-api/v0/info-http-api-controller-v0.js @@ -1,11 +1,11 @@ import { createRequire } from 'module'; -import BaseController from './base-http-api-controller.js'; +import BaseController from '../base-http-api-controller.js'; const require = createRequire(import.meta.url); -const { version } = require('../../../package.json'); +const { version } = require('../../../../package.json'); class InfoController extends BaseController { - handleInfoRequest(req, res) { + handleRequest(_, res) { this.returnResponse(res, 200, { version, }); diff --git a/src/controllers/http-api/local-store-http-api-controller.js b/src/controllers/http-api/v0/local-store-http-api-controller-v0.js similarity index 94% rename from src/controllers/http-api/local-store-http-api-controller.js rename to src/controllers/http-api/v0/local-store-http-api-controller-v0.js index 88f5e4c3dd..fb94771785 100644 --- a/src/controllers/http-api/local-store-http-api-controller.js +++ b/src/controllers/http-api/v0/local-store-http-api-controller-v0.js @@ -1,5 +1,5 @@ -import BaseController from './base-http-api-controller.js'; -import { OPERATION_ID_STATUS } from '../../constants/constants.js'; +import BaseController from '../base-http-api-controller.js'; +import { OPERATION_ID_STATUS } from '../../../constants/constants.js'; class LocalStoreController extends BaseController { constructor(ctx) { @@ -9,7 +9,7 @@ class LocalStoreController extends BaseController { this.dataService = ctx.dataService; } - async handleLocalStoreRequest(req, res) { + async handleRequest(req, res) { const operationId = await this.operationIdService.generateOperationId( OPERATION_ID_STATUS.LOCAL_STORE.LOCAL_STORE_INIT_START, ); diff --git a/src/controllers/http-api/publish-http-api-controller.js b/src/controllers/http-api/v0/publish-http-api-controller-v0.js similarity index 95% rename from src/controllers/http-api/publish-http-api-controller.js rename to src/controllers/http-api/v0/publish-http-api-controller-v0.js index 133823a1a1..91cce81b6b 100644 --- a/src/controllers/http-api/publish-http-api-controller.js +++ b/src/controllers/http-api/v0/publish-http-api-controller-v0.js @@ -1,11 +1,11 @@ -import BaseController from './base-http-api-controller.js'; +import BaseController from '../base-http-api-controller.js'; import { ERROR_TYPE, OPERATION_ID_STATUS, OPERATION_STATUS, CONTENT_ASSET_HASH_FUNCTION_ID, LOCAL_STORE_TYPES, -} from '../../constants/constants.js'; +} from '../../../constants/constants.js'; class PublishController extends BaseController { constructor(ctx) { @@ -16,7 +16,7 @@ class PublishController extends BaseController { this.repositoryModuleManager = ctx.repositoryModuleManager; } - async handlePublishRequest(req, res) { + async handleRequest(req, res) { const operationId = await this.operationIdService.generateOperationId( OPERATION_ID_STATUS.PUBLISH.PUBLISH_START, ); diff --git a/src/controllers/http-api/query-http-api-controller.js b/src/controllers/http-api/v0/query-http-api-controller-v0.js similarity index 84% rename from src/controllers/http-api/query-http-api-controller.js rename to src/controllers/http-api/v0/query-http-api-controller-v0.js index 7fcd2e10b5..0a66186e38 100644 --- a/src/controllers/http-api/query-http-api-controller.js +++ b/src/controllers/http-api/v0/query-http-api-controller-v0.js @@ -1,6 +1,6 @@ -import BaseController from './base-http-api-controller.js'; +import BaseController from '../base-http-api-controller.js'; -import { OPERATION_ID_STATUS } from '../../constants/constants.js'; +import { OPERATION_ID_STATUS } from '../../../constants/constants.js'; class QueryController extends BaseController { constructor(ctx) { @@ -9,7 +9,7 @@ class QueryController extends BaseController { this.operationIdService = ctx.operationIdService; } - async handleQueryRequest(req, res) { + async handleRequest(req, res) { const { query, type: queryType } = req.body; const operationId = await this.operationIdService.generateOperationId( diff --git a/src/controllers/http-api/request-schema/bid-suggestion-schema.js b/src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js similarity index 88% rename from src/controllers/http-api/request-schema/bid-suggestion-schema.js rename to src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js index 4bf997b84b..f9259aa3ef 100644 --- a/src/controllers/http-api/request-schema/bid-suggestion-schema.js +++ b/src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js @@ -1,4 +1,4 @@ -export default (blockchainImplementationNames) => ({ +export default (argumentsObject) => ({ type: 'object', required: [ 'blockchain', @@ -10,7 +10,7 @@ export default (blockchainImplementationNames) => ({ ], properties: { blockchain: { - enum: blockchainImplementationNames, + enum: argumentsObject.blockchainImplementationNames, }, epochsNumber: { type: 'number', diff --git a/src/controllers/http-api/request-schema/get-schema.js b/src/controllers/http-api/v0/request-schema/get-schema-v0.js similarity index 88% rename from src/controllers/http-api/request-schema/get-schema.js rename to src/controllers/http-api/v0/request-schema/get-schema-v0.js index 6d1d6b05a0..a01a9a4e2c 100644 --- a/src/controllers/http-api/request-schema/get-schema.js +++ b/src/controllers/http-api/v0/request-schema/get-schema-v0.js @@ -1,4 +1,4 @@ -import { GET_STATES } from '../../../constants/constants.js'; +import { GET_STATES } from '../../../../constants/constants.js'; export default () => ({ type: 'object', diff --git a/src/controllers/http-api/request-schema/local-store-schema.js b/src/controllers/http-api/v0/request-schema/local-store-schema-v0.js similarity index 83% rename from src/controllers/http-api/request-schema/local-store-schema.js rename to src/controllers/http-api/v0/request-schema/local-store-schema-v0.js index 2c06ae748b..65aab92c27 100644 --- a/src/controllers/http-api/request-schema/local-store-schema.js +++ b/src/controllers/http-api/v0/request-schema/local-store-schema-v0.js @@ -1,6 +1,6 @@ -import { LOCAL_STORE_TYPES } from '../../../constants/constants.js'; +import { LOCAL_STORE_TYPES } from '../../../../constants/constants.js'; -export default (blockchainImplementationNames) => ({ +export default (argumentsObject) => ({ type: 'array', items: { type: 'object', @@ -19,7 +19,7 @@ export default (blockchainImplementationNames) => ({ minItems: 1, }, blockchain: { - enum: blockchainImplementationNames, + enum: argumentsObject.blockchainImplementationNames, }, contract: { type: 'string', diff --git a/src/controllers/http-api/request-schema/publish-schema.js b/src/controllers/http-api/v0/request-schema/publish-schema-v0.js similarity index 87% rename from src/controllers/http-api/request-schema/publish-schema.js rename to src/controllers/http-api/v0/request-schema/publish-schema-v0.js index 068e5018a2..236db2ea5d 100644 --- a/src/controllers/http-api/request-schema/publish-schema.js +++ b/src/controllers/http-api/v0/request-schema/publish-schema-v0.js @@ -1,4 +1,4 @@ -export default (blockchainImplementationNames) => ({ +export default (argumentsObject) => ({ type: 'object', required: ['assertionId', 'assertion', 'blockchain', 'contract', 'tokenId'], properties: { @@ -15,7 +15,7 @@ export default (blockchainImplementationNames) => ({ minItems: 1, }, blockchain: { - enum: blockchainImplementationNames, + enum: argumentsObject.blockchainImplementationNames, }, contract: { type: 'string', diff --git a/src/controllers/http-api/request-schema/query-schema.js b/src/controllers/http-api/v0/request-schema/query-schema-v0.js similarity index 93% rename from src/controllers/http-api/request-schema/query-schema.js rename to src/controllers/http-api/v0/request-schema/query-schema-v0.js index 3f971ba0a2..e245d7d87f 100644 --- a/src/controllers/http-api/request-schema/query-schema.js +++ b/src/controllers/http-api/v0/request-schema/query-schema-v0.js @@ -1,4 +1,4 @@ -import { QUERY_TYPES, TRIPLE_STORE_REPOSITORIES } from '../../../constants/constants.js'; +import { QUERY_TYPES, TRIPLE_STORE_REPOSITORIES } from '../../../../constants/constants.js'; export default () => ({ type: 'object', diff --git a/src/controllers/http-api/request-schema/update-schema.js b/src/controllers/http-api/v0/request-schema/update-schema-v0.js similarity index 87% rename from src/controllers/http-api/request-schema/update-schema.js rename to src/controllers/http-api/v0/request-schema/update-schema-v0.js index 068e5018a2..236db2ea5d 100644 --- a/src/controllers/http-api/request-schema/update-schema.js +++ b/src/controllers/http-api/v0/request-schema/update-schema-v0.js @@ -1,4 +1,4 @@ -export default (blockchainImplementationNames) => ({ +export default (argumentsObject) => ({ type: 'object', required: ['assertionId', 'assertion', 'blockchain', 'contract', 'tokenId'], properties: { @@ -15,7 +15,7 @@ export default (blockchainImplementationNames) => ({ minItems: 1, }, blockchain: { - enum: blockchainImplementationNames, + enum: argumentsObject.blockchainImplementationNames, }, contract: { type: 'string', diff --git a/src/controllers/http-api/result-http-api-controller.js b/src/controllers/http-api/v0/result-http-api-controller-v0.js similarity index 80% rename from src/controllers/http-api/result-http-api-controller.js rename to src/controllers/http-api/v0/result-http-api-controller-v0.js index 120ae86249..de5999f05a 100644 --- a/src/controllers/http-api/result-http-api-controller.js +++ b/src/controllers/http-api/v0/result-http-api-controller-v0.js @@ -1,19 +1,19 @@ -import { OPERATION_ID_STATUS } from '../../constants/constants.js'; -import BaseController from './base-http-api-controller.js'; - -const availableOperations = ['publish', 'get', 'query', 'local-store', 'update']; +import { OPERATION_ID_STATUS } from '../../../constants/constants.js'; +import BaseController from '../base-http-api-controller.js'; class ResultController extends BaseController { constructor(ctx) { super(ctx); this.operationIdService = ctx.operationIdService; + + this.availableOperations = ['publish', 'get', 'query', 'local-store', 'update']; } - async handleOperationResultRequest(req, res) { - if (!availableOperations.includes(req.params.operation)) { + async handleRequest(req, res) { + if (!this.availableOperations.includes(req.params.operation)) { return this.returnResponse(res, 400, { code: 400, - message: `Unsupported operation, available operations are: ${availableOperations}`, + message: `Unsupported operation: ${req.params.operation}, available operations are: ${this.availableOperations}`, }); } @@ -21,7 +21,7 @@ class ResultController extends BaseController { if (!this.operationIdService.operationIdInRightFormat(operationId)) { return this.returnResponse(res, 400, { code: 400, - message: 'Operation id is in wrong format', + message: `Operation id: ${operationId} is in wrong format`, }); } diff --git a/src/controllers/http-api/update-http-api-controller.js b/src/controllers/http-api/v0/update-http-api-controller-v0.js similarity index 95% rename from src/controllers/http-api/update-http-api-controller.js rename to src/controllers/http-api/v0/update-http-api-controller-v0.js index 676950de04..17ecfffcb7 100644 --- a/src/controllers/http-api/update-http-api-controller.js +++ b/src/controllers/http-api/v0/update-http-api-controller-v0.js @@ -1,11 +1,11 @@ -import BaseController from './base-http-api-controller.js'; +import BaseController from '../base-http-api-controller.js'; import { ERROR_TYPE, OPERATION_ID_STATUS, OPERATION_STATUS, CONTENT_ASSET_HASH_FUNCTION_ID, LOCAL_STORE_TYPES, -} from '../../constants/constants.js'; +} from '../../../constants/constants.js'; class UpdateController extends BaseController { constructor(ctx) { @@ -16,7 +16,7 @@ class UpdateController extends BaseController { this.repositoryModuleManager = ctx.repositoryModuleManager; } - async handleUpdateRequest(req, res) { + async handleRequest(req, res) { const operationId = await this.operationIdService.generateOperationId( OPERATION_ID_STATUS.UPDATE.UPDATE_START, ); diff --git a/src/controllers/http-api/v1/.gitkeep b/src/controllers/http-api/v1/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/controllers/http-api/v1/request-schema/.gitkeep b/src/controllers/http-api/v1/request-schema/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/migration/base-migration.js b/src/migration/base-migration.js index 0b17fa6577..afa94b65b6 100644 --- a/src/migration/base-migration.js +++ b/src/migration/base-migration.js @@ -52,6 +52,30 @@ class BaseMigration { ); } + async getMigrationInfo() { + const migrationFolderPath = this.fileService.getMigrationFolderPath(); + const migrationInfoFileName = `${this.migrationName}_info`; + const migrationInfoPath = path.join(migrationFolderPath, migrationInfoFileName); + let migrationInfo = null; + if (await this.fileService.pathExists(migrationInfoPath)) { + migrationInfo = await this.fileService + .readFile(migrationInfoPath, true) + .catch(() => {}); + } + return migrationInfo; + } + + async saveMigrationInfo(migrationInfo) { + const migrationFolderPath = this.fileService.getMigrationFolderPath(); + const migrationInfoFileName = `${this.migrationName}_info`; + await this.fileService.writeContentsToFile( + migrationFolderPath, + migrationInfoFileName, + JSON.stringify(migrationInfo), + false, + ); + } + async executeMigration() { throw Error('Execute migration method not implemented'); } diff --git a/src/migration/migration-executor.js b/src/migration/migration-executor.js new file mode 100644 index 0000000000..aed10123e0 --- /dev/null +++ b/src/migration/migration-executor.js @@ -0,0 +1,268 @@ +import { NODE_ENVIRONMENTS } from '../constants/constants.js'; +import PullBlockchainShardingTableMigration from './pull-sharding-table-migration.js'; +import PrivateAssetsMetadataMigration from './private-assets-metadata-migration.js'; +import TelemetryModuleUserConfigurationMigration from './telemetry-module-user-configuration-migration.js'; +import TripleStoreUserConfigurationMigration from './triple-store-user-configuration-migration.js'; +import ServiceAgreementsMetadataMigration from './service-agreements-metadata-migration.js'; +import RemoveAgreementStartEndTimeMigration from './remove-agreement-start-end-time-migration.js'; +import TripleStoreMetadataMigration from './triple-store-metadata-migration.js'; +import RemoveOldEpochCommandsMigration from './remove-old-epoch-commands-migration.js'; +import PendingStorageMigration from './pending-storage-migration.js'; +import MarkOldBlockchainEventsAsProcessedMigration from './mark-old-blockchain-events-as-processed-migration.js'; +import ServiceAgreementsOpDatabaseMigration from './service-agreements-op-database-migration.js'; + +class MigrationExecutor { + static async executePullShardingTableMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const blockchainModuleManager = container.resolve('blockchainModuleManager'); + const repositoryModuleManager = container.resolve('repositoryModuleManager'); + const validationModuleManager = container.resolve('validationModuleManager'); + + const migration = new PullBlockchainShardingTableMigration( + 'pullShardingTableMigrationV612', + logger, + config, + repositoryModuleManager, + blockchainModuleManager, + validationModuleManager, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executePrivateAssetsMetadataMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + const blockchainModuleManager = container.resolve('blockchainModuleManager'); + const tripleStoreService = container.resolve('tripleStoreService'); + const serviceAgreementService = container.resolve('serviceAgreementService'); + const ualService = container.resolve('ualService'); + const dataService = container.resolve('dataService'); + + const migration = new PrivateAssetsMetadataMigration( + 'privateAssetsMetadataMigration', + logger, + config, + tripleStoreService, + blockchainModuleManager, + serviceAgreementService, + ualService, + dataService, + ); + + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + logger.info('Node will now restart!'); + MigrationExecutor.exitNode(1); + } + } + + static async executeTelemetryModuleUserConfigurationMigration(logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const migration = new TelemetryModuleUserConfigurationMigration( + 'telemetryModuleUserConfigurationMigration', + logger, + config, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + logger.info('Node will now restart!'); + MigrationExecutor.exitNode(1); + } + } + + static async executeTripleStoreUserConfigurationMigration(logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const migration = new TripleStoreUserConfigurationMigration( + 'tripleStoreUserConfigurationMigration', + logger, + config, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + logger.info('Node will now restart!'); + MigrationExecutor.exitNode(1); + } + } + + static async executeServiceAgreementsMetadataMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const blockchainModuleManager = container.resolve('blockchainModuleManager'); + const repositoryModuleManager = container.resolve('repositoryModuleManager'); + const tripleStoreService = container.resolve('tripleStoreService'); + const serviceAgreementService = container.resolve('serviceAgreementService'); + const ualService = container.resolve('ualService'); + + const migration = new ServiceAgreementsMetadataMigration( + 'serviceAgreementsMetadataMigration', + logger, + config, + tripleStoreService, + blockchainModuleManager, + repositoryModuleManager, + serviceAgreementService, + ualService, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executeRemoveAgreementStartEndTimeMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const tripleStoreService = container.resolve('tripleStoreService'); + + const migration = new RemoveAgreementStartEndTimeMigration( + 'removeAgreementStartEndTimeMigration', + logger, + config, + tripleStoreService, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executeTripleStoreMetadataMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + const blockchainModuleManager = container.resolve('blockchainModuleManager'); + const tripleStoreService = container.resolve('tripleStoreService'); + const serviceAgreementService = container.resolve('serviceAgreementService'); + const ualService = container.resolve('ualService'); + const dataService = container.resolve('dataService'); + + const migration = new TripleStoreMetadataMigration( + 'tripleStoreMetadataMigration', + logger, + config, + tripleStoreService, + blockchainModuleManager, + serviceAgreementService, + ualService, + dataService, + ); + + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executeRemoveOldEpochCommandsMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const repositoryModuleManager = container.resolve('repositoryModuleManager'); + + const migration = new RemoveOldEpochCommandsMigration( + 'removeOldEpochCommandsMigration', + logger, + config, + repositoryModuleManager, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executePendingStorageMigration(logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const migration = new PendingStorageMigration('pendingStorageMigration', logger, config); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executeMarkOldBlockchainEventsAsProcessedMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const repositoryModuleManager = container.resolve('repositoryModuleManager'); + + const migration = new MarkOldBlockchainEventsAsProcessedMigration( + 'markOldBlockchainEventsAsProcessedMigration', + logger, + config, + repositoryModuleManager, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static async executeServiceAgreementsOpDatabaseMigration(container, logger, config) { + // todo should we also exclude testnet? + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVELOPMENT || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TEST + ) + return; + + const blockchainModuleManager = container.resolve('blockchainModuleManager'); + const repositoryModuleManager = container.resolve('repositoryModuleManager'); + const serviceAgreementService = container.resolve('serviceAgreementService'); + const ualService = container.resolve('ualService'); + + const migration = new ServiceAgreementsOpDatabaseMigration( + 'serviceAgreementsOpDatabaseMigration', + logger, + config, + blockchainModuleManager, + repositoryModuleManager, + serviceAgreementService, + ualService, + ); + if (!(await migration.migrationAlreadyExecuted())) { + await migration.migrate(); + } + } + + static exitNode(code = 0) { + process.exit(code); + } +} + +export default MigrationExecutor; diff --git a/src/migration/service-agreements-op-database-migration.js b/src/migration/service-agreements-op-database-migration.js new file mode 100644 index 0000000000..d5dd752a5b --- /dev/null +++ b/src/migration/service-agreements-op-database-migration.js @@ -0,0 +1,137 @@ +/* eslint-disable no-await-in-loop */ +import BaseMigration from './base-migration.js'; + +let wrongAgreementsCount = 0; +const MAX_BATCH_SIZE = 10000; +const CONCURRENCY = 3; + +class ServiceAgreementsOpDatabaseMigration extends BaseMigration { + constructor( + migrationName, + logger, + config, + blockchainModuleManager, + repositoryModuleManager, + serviceAgreementService, + ualService, + ) { + super(migrationName, logger, config); + this.blockchainModuleManager = blockchainModuleManager; + this.repositoryModuleManager = repositoryModuleManager; + this.serviceAgreementService = serviceAgreementService; + this.ualService = ualService; + } + + async executeMigration() { + let migrationInfo = await this.getMigrationInfo(); + if (!migrationInfo?.lastProcessedTokenId) { + migrationInfo = { + lastProcessedTokenId: 0, + }; + } + + const numberOfActiveServiceAgreements = + await this.repositoryModuleManager.getNumberOfActiveServiceAgreements(); + let processed = 0; + const batchSize = + numberOfActiveServiceAgreements > MAX_BATCH_SIZE + ? MAX_BATCH_SIZE + : numberOfActiveServiceAgreements; + + while (processed < numberOfActiveServiceAgreements) { + const serviceAgreementsToProcess = + await this.repositoryModuleManager.getServiceAgreements( + migrationInfo.lastProcessedTokenId, + batchSize, + ); + let promises = []; + + for (const serviceAgreement of serviceAgreementsToProcess) { + promises.push(this.processServiceAgreement(serviceAgreement)); + + if ( + promises.length >= CONCURRENCY || + promises.length === serviceAgreementsToProcess.length + ) { + try { + await Promise.all(promises); + } catch (error) { + this.logger.warn( + `Unable to process invalid service agreements. Error: ${error}`, + ); + } + promises = []; + migrationInfo.lastProcessedTokenId = + serviceAgreementsToProcess.slice(-1)[0].tokenId; + await this.saveMigrationInfo(migrationInfo); + this.logger.trace( + `${this.migrationName} Last token id processed ${migrationInfo.lastProcessedTokenId}.`, + ); + } + } + + processed += batchSize; + } + + this.logger.trace( + `${this.migrationName} Total number of processed agreements ${processed}. Found invalid agreements: ${wrongAgreementsCount}`, + ); + } + + async processServiceAgreement(serviceAgreement) { + const updatedServiceAgreement = {}; + let updated = false; + const keyword = await this.ualService.calculateLocationKeyword( + serviceAgreement.blockchainId, + serviceAgreement.assetStorageContractAddress, + serviceAgreement.tokenId, + ); + + if (serviceAgreement.keyword !== keyword) { + updatedServiceAgreement.keyword = keyword; + updated = true; + } + + const agreementId = await this.serviceAgreementService.generateId( + serviceAgreement.blockchainId, + serviceAgreement.assetStorageContractAddress, + serviceAgreement.tokenId, + keyword, + serviceAgreement.hashFunctionId, + ); + + if (serviceAgreement.agreementId !== agreementId) { + updatedServiceAgreement.agreementId = agreementId; + updated = true; + } + + const assertionIds = await this.blockchainModuleManager.getAssertionIds( + serviceAgreement.blockchain, + serviceAgreement.assetStorageContractAddress, + serviceAgreement.tokenId, + ); + const stateIndex = assertionIds.length - 1; + + if (serviceAgreement.assertionId !== assertionIds[stateIndex]) { + updatedServiceAgreement.assertionId = assertionIds[stateIndex]; + updated = true; + } + + if (serviceAgreement.stateIndex !== stateIndex) { + updatedServiceAgreement.stateIndex = stateIndex; + updated = true; + } + if (updated) { + await this.repositoryModuleManager.updateServiceAgreementForTokenId( + serviceAgreement.tokenId, + updatedServiceAgreement.agreementId ?? serviceAgreement.agreementId, + updatedServiceAgreement.keyword ?? serviceAgreement.keyword, + updatedServiceAgreement.assertionId ?? serviceAgreement.assertionId, + updatedServiceAgreement.stateIndex ?? serviceAgreement.stateIndex, + ); + wrongAgreementsCount += 1; + } + } +} + +export default ServiceAgreementsOpDatabaseMigration; diff --git a/src/migration/telemetry-module-user-configuration-migration.js b/src/migration/telemetry-module-user-configuration-migration.js new file mode 100644 index 0000000000..a49cc393af --- /dev/null +++ b/src/migration/telemetry-module-user-configuration-migration.js @@ -0,0 +1,45 @@ +import appRootPath from 'app-root-path'; +import path from 'path'; +import BaseMigration from './base-migration.js'; + +class TelemetryModuleUserConfigurationMigration extends BaseMigration { + async executeMigration() { + const configurationFolderPath = path.join(appRootPath.path, '..'); + const configurationFilePath = path.join( + configurationFolderPath, + this.config.configFilename, + ); + + const userConfiguration = await this.fileService.readFile(configurationFilePath, true); + + let newTelemetryConfig; + + if ('telemetry' in userConfiguration) { + const oldConfigTelemetry = userConfiguration.telemetry; + newTelemetryConfig = { + enabled: oldConfigTelemetry.enabled, + implementation: { + 'ot-telemetry': { + enabled: oldConfigTelemetry.enabled, + package: './telemetry/implementation/ot-telemetry.js', + config: { + sendTelemetryData: oldConfigTelemetry.sendTelemetryData, + signalingServerUrl: oldConfigTelemetry.signalingServerUrl, + }, + }, + }, + }; + + delete userConfiguration.telemetry; + userConfiguration.modules.telemetry = newTelemetryConfig; + + await this.fileService.writeContentsToFile( + configurationFolderPath, + this.config.configFilename, + JSON.stringify(userConfiguration, null, 4), + ); + } + } +} + +export default TelemetryModuleUserConfigurationMigration; diff --git a/src/modules/base-module-manager.js b/src/modules/base-module-manager.js index e96161999c..2bdc901d6a 100644 --- a/src/modules/base-module-manager.js +++ b/src/modules/base-module-manager.js @@ -91,7 +91,7 @@ class BaseModuleManager { delete this.handlers[name]; } - getModuleConfiguration(name) { + getModuleConfiguration(name = null) { return this.getImplementation(name).config; } } diff --git a/src/modules/blockchain/implementation/web3-service.js b/src/modules/blockchain/implementation/web3-service.js index e003f881d8..c53d56d2cd 100644 --- a/src/modules/blockchain/implementation/web3-service.js +++ b/src/modules/blockchain/implementation/web3-service.js @@ -1,17 +1,24 @@ -import { ethers } from 'ethers'; +import { ethers, BigNumber } from 'ethers'; import axios from 'axios'; import async from 'async'; import { setTimeout as sleep } from 'timers/promises'; import { createRequire } from 'module'; import { + SOLIDITY_ERROR_STRING_PREFIX, + SOLIDITY_PANIC_CODE_PREFIX, + SOLIDITY_PANIC_REASONS, + ZERO_PREFIX, DEFAULT_BLOCKCHAIN_EVENT_SYNC_PERIOD_IN_MILLS, MAXIMUM_NUMBERS_OF_BLOCKS_TO_FETCH, TRANSACTION_QUEUE_CONCURRENCY, - FIXED_GAS_LIMIT_METHODS, TRANSACTION_POLLING_TIMEOUT_MILLIS, TRANSACTION_CONFIRMATIONS, BLOCK_TIME_MILLIS, + WS_RPC_PROVIDER_PRIORITY, + HTTP_RPC_PROVIDER_PRIORITY, + FALLBACK_PROVIDER_QUORUM, + RPC_PROVIDER_STALL_TIMEOUT, } from '../../../constants/constants.js'; const require = createRequire(import.meta.url); @@ -50,11 +57,11 @@ class Web3Service { this.config = config; this.logger = logger; - this.rpcNumber = 0; this.initializeTransactionQueue(TRANSACTION_QUEUE_CONCURRENCY); await this.initializeWeb3(); this.startBlock = await this.getBlockNumber(); await this.initializeContracts(); + this.initializeProviderDebugging(); } initializeTransactionQueue(concurrency) { @@ -86,41 +93,52 @@ class Web3Service { } async initializeWeb3() { - let tries = 0; - let isRpcConnected = false; - while (!isRpcConnected) { - if (tries >= this.config.rpcEndpoints.length) { - throw Error('RPC initialization failed'); - } + const providers = []; + for (const rpcEndpoint of this.config.rpcEndpoints) { + const isWebSocket = rpcEndpoint.startsWith('ws'); + const Provider = isWebSocket + ? ethers.providers.WebSocketProvider + : ethers.providers.JsonRpcProvider; + const priority = isWebSocket ? WS_RPC_PROVIDER_PRIORITY : HTTP_RPC_PROVIDER_PRIORITY; try { - if (this.config.rpcEndpoints[this.rpcNumber].startsWith('ws')) { - this.provider = new ethers.providers.WebSocketProvider( - this.config.rpcEndpoints[this.rpcNumber], - ); - } else { - this.provider = new ethers.providers.JsonRpcProvider( - this.config.rpcEndpoints[this.rpcNumber], - ); - } + const provider = new Provider(rpcEndpoint); // eslint-disable-next-line no-await-in-loop - await this.providerReady(); - isRpcConnected = true; + await provider.getNetwork(); + + providers.push({ + provider, + priority, + weight: 1, + stallTimeout: RPC_PROVIDER_STALL_TIMEOUT, + }); + + this.logger.debug(`Connected to the blockchain RPC: ${rpcEndpoint}.`); } catch (e) { - this.logger.warn( - `Unable to connect to blockchain rpc : ${ - this.config.rpcEndpoints[this.rpcNumber] - }.`, - ); - tries += 1; - this.rpcNumber = (this.rpcNumber + 1) % this.config.rpcEndpoints.length; + this.logger.warn(`Unable to connect to the blockchain RPC: ${rpcEndpoint}.`); } } + try { + this.provider = new ethers.providers.FallbackProvider( + providers, + FALLBACK_PROVIDER_QUORUM, + ); + + // eslint-disable-next-line no-await-in-loop + await this.providerReady(); + } catch (e) { + throw Error( + `RPC Fallback Provider initialization failed. Fallback Provider quorum: ${FALLBACK_PROVIDER_QUORUM}. Error: ${e.message}.`, + ); + } + this.wallet = new ethers.Wallet(this.getPrivateKey(), this.provider); } async initializeContracts() { + this.contractAddresses = {}; + this.logger.info( `Initializing contracts with hub contract address: ${this.config.hubContractAddress}`, ); @@ -129,6 +147,7 @@ class Web3Service { ABIs.Hub, this.wallet, ); + this.contractAddresses[this.config.hubContractAddress] = this.HubContract; const contractsArray = await this.callContractFunction( this.HubContract, @@ -161,19 +180,71 @@ class Web3Service { }); this.logger.info(`Contracts initialized`); - this.logger.debug( - `Connected to blockchain rpc : ${this.config.rpcEndpoints[this.rpcNumber]}.`, - ); await this.logBalances(); } + initializeProviderDebugging() { + this.provider.on('debug', (info) => { + const { method } = info.request; + + if (['call', 'estimateGas'].includes(method)) { + const contractInstance = this.contractAddresses[info.request.params.transaction.to]; + const inputData = info.request.params.transaction.data; + const decodedInputData = this._decodeInputData( + inputData, + contractInstance.interface, + ); + const functionFragment = contractInstance.interface.getFunction( + inputData.slice(0, 10), + ); + const functionName = functionFragment.name; + const inputs = functionFragment.inputs.map( + (input, i) => `${input.name}=${decodedInputData[i]}`, + ); + if (info.backend.error) { + const decodedErrorData = this._decodeErrorData( + info.backend.error, + contractInstance.interface, + ); + this.logger.debug( + `${functionName}(${inputs}) ${method} has failed; Error: ${decodedErrorData}; ` + + `RPC: ${info.backend.provider.connection.url}.`, + ); + } else if (info.backend.result !== undefined) { + let message = `${functionName}(${inputs}) ${method} has been successfully executed; `; + + if (info.backend.result !== null && method !== 'estimateGas') { + try { + const decodedResultData = this._decodeResultData( + inputData.slice(0, 10), + info.backend.result, + contractInstance.interface, + ); + message += `Result: ${decodedResultData}; `; + } catch (error) { + this.logger.warn( + `Unable to decode result data for. Message: ${message}`, + ); + } + } + + message += `RPC: ${info.backend.provider.connection.url}.`; + + this.logger.debug(message); + } + } + }); + } + initializeAssetStorageContract(assetStorageAddress) { this.assetStorageContracts[assetStorageAddress.toLowerCase()] = new ethers.Contract( assetStorageAddress, ABIs.ContentAssetStorage, this.wallet, ); + this.contractAddresses[assetStorageAddress] = + this.assetStorageContracts[assetStorageAddress.toLowerCase()]; } initializeScoringContract(id, contractAddress) { @@ -185,6 +256,7 @@ class Web3Service { ABIs[contractName], this.wallet, ); + this.contractAddresses[contractAddress] = this.scoringFunctionsContracts[id]; } else { this.logger.trace( `Skipping initialisation of contract with id: ${id}, address: ${contractAddress}`, @@ -199,6 +271,7 @@ class Web3Service { ABIs[contractName], this.wallet, ); + this.contractAddresses[contractAddress] = this[`${contractName}Contract`]; } else { this.logger.trace( `Skipping initialisation of contract: ${contractName}, address: ${contractAddress}`, @@ -333,8 +406,18 @@ class Web3Service { // eslint-disable-next-line no-await-in-loop result = await contractInstance[functionName](...args); } catch (error) { - // eslint-disable-next-line no-await-in-loop - await this.handleError(error, functionName); + const decodedErrorData = this._decodeErrorData(error, contractInstance.interface); + + const functionFragment = contractInstance.interface.getFunction( + error.transaction.data.slice(0, 10), + ); + const inputs = functionFragment.inputs.map( + (input, i) => `${input.name}=${args[i]}`, + ); + + throw new Error( + `Call ${functionName}(${inputs}) failed, reason: ${decodedErrorData}`, + ); } } @@ -345,57 +428,187 @@ class Web3Service { let result; let gasPrice = (await this.getGasPrice()) ?? this.convertToWei(20, 'gwei'); let transactionRetried = false; + while (result === undefined) { + let gasLimit; + try { /* eslint-disable no-await-in-loop */ - let gasLimit; - - if (FIXED_GAS_LIMIT_METHODS[functionName]) { - gasLimit = FIXED_GAS_LIMIT_METHODS[functionName]; - } else { - gasLimit = await contractInstance.estimateGas[functionName](...args); - } + gasLimit = await contractInstance.estimateGas[functionName](...args); + } catch (error) { + const decodedErrorData = this._decodeErrorData(error, contractInstance.interface); - const gas = gasLimit ?? this.convertToWei(900, 'kwei'); + const functionFragment = contractInstance.interface.getFunction( + error.transaction.data.slice(0, 10), + ); + const inputs = functionFragment.inputs.map( + (input, i) => `${input.name}=${args[i]}`, + ); - this.logger.info( - 'Sending signed transaction to blockchain, calling method: ' + - `${functionName} with gas limit: ${gas.toString()} and gasPrice ${gasPrice.toString()}. Transaction queue length: ${this.getTransactionQueueLength()}`, + throw new Error( + `Gas estimation ${functionName}(${inputs}) failed, reason: ${decodedErrorData}`, ); + } + + gasLimit = gasLimit ?? this.convertToWei(900, 'kwei'); + + this.logger.debug( + `Sending signed transaction ${functionName} to the blockchain ` + + `with gas limit: ${gasLimit.toString()} and gasPrice ${gasPrice.toString()}. ` + + `Transaction queue length: ${this.getTransactionQueueLength()}.`, + ); + + try { const tx = await contractInstance[functionName](...args, { gasPrice, - gasLimit: gas, + gasLimit, }); result = await this.provider.waitForTransaction( tx.hash, TRANSACTION_CONFIRMATIONS, TRANSACTION_POLLING_TIMEOUT_MILLIS, ); - if (result?.status === 0) { - throw Error(); + + if (result.status === 0) { + await this.provider.call(tx, tx.blockNumber); } } catch (error) { - this.logger.warn( - `Failed executing smart contract function ${functionName}. Error: ${error.message}`, - ); + const decodedErrorData = this._decodeErrorData(error, contractInstance.interface); if ( !transactionRetried && (error.message.includes(`timeout exceeded`) || error.message.includes(`Pool(TooLowPriority`)) ) { gasPrice = Math.ceil(gasPrice * 1.2); - this.logger.warn( - `Retrying to execute smart contract function ${functionName} with gasPrice: ${gasPrice}`, - ); transactionRetried = true; } else { - await this.handleError(error, functionName); + throw new Error(`Transaction reverted, reason: ${decodedErrorData}`); } } } return result; } + _getErrorData(error) { + let nestedError = error; + while (nestedError && nestedError.error) { + nestedError = nestedError.error; + } + const errorData = nestedError.data; + + if (errorData === undefined) { + throw error; + } + + let returnData = typeof errorData === 'string' ? errorData : errorData.data; + + if (typeof returnData === 'object' && returnData.data) { + returnData = returnData.data; + } + + if (returnData === undefined || typeof returnData !== 'string') { + throw error; + } + + return returnData; + } + + _decodeInputData(inputData, contractInterface) { + if (inputData === ZERO_PREFIX) { + return 'Empty input data.'; + } + + return contractInterface.decodeFunctionData(inputData.slice(0, 10), inputData); + } + + _decodeErrorData(evmError, contractInterface) { + let errorData; + + try { + errorData = this._getErrorData(evmError); + } catch (error) { + return error.message; + } + + // Handle empty error data + if (errorData === ZERO_PREFIX) { + return 'Empty error data.'; + } + + // Handle standard solidity string error + if (errorData.startsWith(SOLIDITY_ERROR_STRING_PREFIX)) { + const encodedReason = errorData.slice(SOLIDITY_ERROR_STRING_PREFIX.length); + try { + return ethers.utils.defaultAbiCoder.decode(['string'], `0x${encodedReason}`)[0]; + } catch (error) { + return error.message; + } + } + + // Handle solidity panic code + if (errorData.startsWith(SOLIDITY_PANIC_CODE_PREFIX)) { + const encodedReason = errorData.slice(SOLIDITY_PANIC_CODE_PREFIX.length); + let code; + try { + [code] = ethers.utils.defaultAbiCoder.decode(['uint256'], `0x${encodedReason}`); + } catch (error) { + return error.message; + } + + return SOLIDITY_PANIC_REASONS[code] ?? 'Unknown Solidity panic code.'; + } + + // Try parsing a custom error using the contract ABI + try { + const decodedCustomError = contractInterface.parseError(errorData); + const formattedArgs = decodedCustomError.errorFragment.inputs + .map((input, i) => { + const argName = input.name; + const argValue = this._formatCustomErrorArgument(decodedCustomError.args[i]); + return `${argName}=${argValue}`; + }) + .join(', '); + return `custom error ${decodedCustomError.name}(${formattedArgs})`; + } catch (error) { + return `Failed to decode custom error data. Error: ${error}`; + } + } + + _decodeResultData(fragment, resultData, contractInterface) { + if (resultData === ZERO_PREFIX) { + return 'Empty input data.'; + } + + return contractInterface.decodeFunctionResult(fragment, resultData); + } + + _formatCustomErrorArgument(value) { + if (value === null || value === undefined) { + return 'null'; + } + + if (typeof value === 'string') { + return value; + } + + if (typeof value === 'number' || BigNumber.isBigNumber(value)) { + return value.toString(); + } + + if (Array.isArray(value)) { + return `[${value.map((v) => this._formatCustomErrorArgument(v)).join(', ')}]`; + } + + if (typeof value === 'object') { + const formattedEntries = Object.entries(value).map( + ([k, v]) => `${k}: ${this._formatCustomErrorArgument(v)}`, + ); + return `{${formattedEntries.join(', ')}}`; + } + + return value.toString(); + } + async getAllPastEvents( blockchainId, contractName, @@ -806,32 +1019,10 @@ class Web3Service { } async restartService() { - this.rpcNumber = (this.rpcNumber + 1) % this.config.rpcEndpoints.length; - this.logger.warn( - `There was an issue with current blockchain rpc. Connecting to ${ - this.config.rpcEndpoints[this.rpcNumber] - }`, - ); await this.initializeWeb3(); await this.initializeContracts(); } - async handleError(error, functionName) { - let isRpcError = false; - try { - await this.provider.getNetwork(); - } catch (rpcError) { - isRpcError = true; - this.logger.warn( - `Unable to execute smart contract function ${functionName} using blockchain rpc : ${ - this.config.rpcEndpoints[this.rpcNumber] - }.`, - ); - await this.restartService(); - } - if (!isRpcError) throw error; - } - async getUpdateCommitWindowDuration() { const commitWindowDurationPerc = await this.callContractFunction( this.ParametersStorageContract, diff --git a/src/modules/http-client/http-client-module-manager.js b/src/modules/http-client/http-client-module-manager.js index ef3c54a39b..aef322cf6d 100644 --- a/src/modules/http-client/http-client-module-manager.js +++ b/src/modules/http-client/http-client-module-manager.js @@ -22,6 +22,18 @@ class HttpClientModuleManager extends BaseModuleManager { } } + use(route, callback, options = {}) { + if (this.initialized) { + return this.getImplementation().module.use(route, callback, options); + } + } + + createRouterInstance() { + if (this.initialized) { + return this.getImplementation().module.createRouterInstance(); + } + } + sendResponse(res, status, returnObject) { if (this.initialized) { return this.getImplementation().module.sendResponse(res, status, returnObject); @@ -34,6 +46,12 @@ class HttpClientModuleManager extends BaseModuleManager { } } + selectMiddlewares(options) { + if (this.initialized) { + return this.getImplementation().module.selectMiddlewares(options); + } + } + initializeBeforeMiddlewares() { if (this.initialized) { return this.getImplementation().module.initializeBeforeMiddlewares(this.authService); diff --git a/src/modules/http-client/implementation/express-http-client.js b/src/modules/http-client/implementation/express-http-client.js index d14fa2b93a..cd37b698c2 100644 --- a/src/modules/http-client/implementation/express-http-client.js +++ b/src/modules/http-client/implementation/express-http-client.js @@ -24,6 +24,14 @@ class ExpressHttpClient { this.app.post(route, ...this.selectMiddlewares(options), callback); } + use(route, callback, options) { + this.app.use(route, ...this.selectMiddlewares(options), callback); + } + + createRouterInstance() { + return express.Router(); + } + sendResponse(res, status, returnObject) { res.status(status); res.send(returnObject); diff --git a/src/modules/http-client/implementation/middleware/authentication-middleware.js b/src/modules/http-client/implementation/middleware/authentication-middleware.js index 87bdf99454..bb3ce98246 100644 --- a/src/modules/http-client/implementation/middleware/authentication-middleware.js +++ b/src/modules/http-client/implementation/middleware/authentication-middleware.js @@ -14,7 +14,11 @@ const parseIp = (req) => { }; export default (authService) => async (req, res, next) => { - const operation = req.url.split('/')[1].split('?')[0].toUpperCase(); + // eslint-disable-next-line no-useless-escape + const match = req.path.match(/^\/(?:v[0-9]+\/)?([^\/\?]+)/); + if (!match) return res.status(404).send('Not found.'); + + const operation = match[0].substring(1); if (authService.isPublicOperation(operation)) { return next(); diff --git a/src/modules/http-client/implementation/middleware/authorization-middleware.js b/src/modules/http-client/implementation/middleware/authorization-middleware.js index 3c9c03ca58..5c92020f15 100644 --- a/src/modules/http-client/implementation/middleware/authorization-middleware.js +++ b/src/modules/http-client/implementation/middleware/authorization-middleware.js @@ -5,7 +5,11 @@ const getToken = (req) => { }; export default (authService) => async (req, res, next) => { - const operation = req.url.split('/')[1].split('?')[0].toUpperCase(); + // eslint-disable-next-line no-useless-escape + const match = req.path.match(/^\/(?:v[0-9]+\/)?([^\/\?]+)/); + if (!match) return res.status(404).send('Not found.'); + + const operation = match[0].substring(1); if (authService.isPublicOperation(operation)) { return next(); diff --git a/src/modules/module-config-validation.js b/src/modules/module-config-validation.js index 4eaaf02b42..fc2cd00619 100644 --- a/src/modules/module-config-validation.js +++ b/src/modules/module-config-validation.js @@ -8,9 +8,12 @@ class ModuleConfigValidation { validateModule(name, config) { this.validateRequiredModule(name, config); - const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1); - this[`validate${capitalizedName}`](config); + if (typeof this[`validate${capitalizedName}`] === 'function') { + this[`validate${capitalizedName}`](config); + } else { + throw Error(`Missing validation for ${capitalizedName}`); + } } validateAutoUpdater() { @@ -68,6 +71,10 @@ class ModuleConfigValidation { this.logger.warn(message); } } + + validateTelemetry() { + return true; + } } export default ModuleConfigValidation; diff --git a/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js b/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js index fdca41bf7c..deec201839 100644 --- a/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js +++ b/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js @@ -23,7 +23,7 @@ class ServiceAgreementRepository { async updateServiceAgreementRecord( blockchainId, - contract, + assetStorageContractAddress, tokenId, agreementId, startTime, @@ -40,7 +40,7 @@ class ServiceAgreementRepository { ) { return this.model.upsert({ blockchainId, - assetStorageContractAddress: contract, + assetStorageContractAddress, tokenId, agreementId, startTime, @@ -57,6 +57,22 @@ class ServiceAgreementRepository { }); } + async updateServiceAgreementForTokenId(tokenId, agreementId, keyword, assertionId, stateIndex) { + return this.model.update( + { + agreementId, + keyword, + assertionId, + stateIndex, + }, + { + where: { + tokenId, + }, + }, + ); + } + async bulkCreateServiceAgreementRecords(serviceAgreements) { return this.model.bulkCreate(serviceAgreements, { validate: true, @@ -202,6 +218,20 @@ class ServiceAgreementRepository { raw: true, }); } + + async getNumberOfActiveServiceAgreements() { + return this.model.count(); + } + + async getServiceAgreements(fromTokenId, batchSize) { + return this.model.findAll({ + where: { + tokenId: { [Sequelize.Op.gte]: fromTokenId }, + }, + limit: batchSize, + order: [['token_id', 'asc']], + }); + } } export default ServiceAgreementRepository; diff --git a/src/modules/repository/repository-module-manager.js b/src/modules/repository/repository-module-manager.js index 74f832901b..5cf4a83153 100644 --- a/src/modules/repository/repository-module-manager.js +++ b/src/modules/repository/repository-module-manager.js @@ -325,6 +325,18 @@ class RepositoryModuleManager extends BaseModuleManager { } } + async updateServiceAgreementForTokenId(tokenId, agreementId, keyword, assertionId, stateIndex) { + if (this.initialized) { + return this.getRepository('service_agreement').updateServiceAgreementForTokenId( + tokenId, + agreementId, + keyword, + assertionId, + stateIndex, + ); + } + } + async bulkCreateServiceAgreementRecords(records) { if (this.initialized) { return this.getRepository('service_agreement').bulkCreateServiceAgreementRecords( @@ -405,6 +417,14 @@ class RepositoryModuleManager extends BaseModuleManager { epochsNumber, ); } + + async getNumberOfActiveServiceAgreements() { + return this.getRepository('service_agreement').getNumberOfActiveServiceAgreements(); + } + + async getServiceAgreements(fromTokenId, batchSize) { + return this.getRepository('service_agreement').getServiceAgreements(fromTokenId, batchSize); + } } export default RepositoryModuleManager; diff --git a/src/modules/telemetry/implementation/ot-telemetry.js b/src/modules/telemetry/implementation/ot-telemetry.js new file mode 100644 index 0000000000..c4460c7572 --- /dev/null +++ b/src/modules/telemetry/implementation/ot-telemetry.js @@ -0,0 +1,29 @@ +import axios from 'axios'; + +class OTTelemetry { + async initialize(config, logger) { + this.config = config; + this.logger = logger; + } + + listenOnEvents(eventEmitter, onEventReceived) { + return eventEmitter.on('operation_status_changed', onEventReceived); + } + + async sendTelemetryData(nodeData, events) { + const signalingMessage = { nodeData, events }; + const config = { + method: 'post', + url: this.config.signalingServerUrl, + headers: { + 'Content-Type': 'application/json', + }, + data: JSON.stringify(signalingMessage), + }; + const response = await axios(config); + const isSuccess = response.status === 200; + return isSuccess; + } +} + +export default OTTelemetry; diff --git a/src/modules/telemetry/telemetry-module-manager.js b/src/modules/telemetry/telemetry-module-manager.js new file mode 100644 index 0000000000..f5ef04377e --- /dev/null +++ b/src/modules/telemetry/telemetry-module-manager.js @@ -0,0 +1,29 @@ +import BaseModuleManager from '../base-module-manager.js'; + +class TelemetryModuleManager extends BaseModuleManager { + constructor(ctx) { + super(ctx); + this.eventEmitter = ctx.eventEmitter; + } + + getName() { + return 'telemetry'; + } + + listenOnEvents(onEventReceived) { + if (this.config.modules.telemetry.enabled && this.initialized) { + return this.getImplementation().module.listenOnEvents( + this.eventEmitter, + onEventReceived, + ); + } + } + + async sendTelemetryData(nodeData, events) { + if (this.initialized) { + return this.getImplementation().module.sendTelemetryData(nodeData, events); + } + } +} + +export default TelemetryModuleManager; diff --git a/src/service/auth-service.js b/src/service/auth-service.js index 729923934c..05c6c3093e 100644 --- a/src/service/auth-service.js +++ b/src/service/auth-service.js @@ -62,7 +62,15 @@ class AuthService { return false; } - return this._authConfig.publicOperations.includes(operationName); + const lowerCaseOperationName = operationName.toLowerCase(); + + return this._authConfig.publicOperations.some((publicOperation) => { + const lowerCasePublicOperation = publicOperation.toLowerCase(); + return ( + lowerCasePublicOperation === `v0/${lowerCaseOperationName}` || + lowerCasePublicOperation === lowerCaseOperationName + ); + }); } /** diff --git a/src/service/blockchain-event-listener-service.js b/src/service/blockchain-event-listener-service.js index c5a252be41..29d63ff71a 100644 --- a/src/service/blockchain-event-listener-service.js +++ b/src/service/blockchain-event-listener-service.js @@ -488,6 +488,7 @@ class BlockchainEventListenerService { blockchain, contract, tokenId, + assertionId, ); const storePromises = []; @@ -559,12 +560,15 @@ class BlockchainEventListenerService { await Promise.all(storePromises); // remove asset from pending storage - await this.pendingStorageService.removeCachedAssertion( - pendingRepository, - blockchain, - contract, - tokenId, - ); + if (cachedData) { + await this.pendingStorageService.removeCachedAssertion( + pendingRepository, + blockchain, + contract, + tokenId, + assertionId, + ); + } } } diff --git a/src/service/file-service.js b/src/service/file-service.js index aa1c5be91b..7d92ce8a84 100644 --- a/src/service/file-service.js +++ b/src/service/file-service.js @@ -90,8 +90,7 @@ class FileService { } async removeFolder(folderPath) { - // this.logger.trace(`Removing folder at path: ${folderPath}`); - + this.logger.debug(`Removing folder at path: ${folderPath}`); try { await rm(folderPath, { recursive: true }); return true; @@ -146,19 +145,16 @@ class FileService { tokenId, ); - let pendingStorageFileName; - if (assertionId === undefined) { - [pendingStorageFileName] = await this.readDirectory(pendingStorageFolder); - } else { - pendingStorageFileName = assertionId; - } - - return path.join(pendingStorageFolder, pendingStorageFileName); + return path.join(pendingStorageFolder, assertionId); } getArchiveFolderPath(subFolder) { return path.join(this.getDataFolderPath(), ARCHIVE_FOLDER_NAME, subFolder); } + + getParentDirectory(filePath) { + return path.dirname(filePath); + } } export default FileService; diff --git a/src/service/json-schema-service.js b/src/service/json-schema-service.js index 3f7186500c..859d9edab2 100644 --- a/src/service/json-schema-service.js +++ b/src/service/json-schema-service.js @@ -1,37 +1,110 @@ -import publishSchema from '../controllers/http-api/request-schema/publish-schema.js'; -import updateSchema from '../controllers/http-api/request-schema/update-schema.js'; -import getSchema from '../controllers/http-api/request-schema/get-schema.js'; -import querySchema from '../controllers/http-api/request-schema/query-schema.js'; -import bidSuggestionSchema from '../controllers/http-api/request-schema/bid-suggestion-schema.js'; -import localStoreSchema from '../controllers/http-api/request-schema/local-store-schema.js'; +import path from 'path'; +import appRootPath from 'app-root-path'; class JsonSchemaService { constructor(ctx) { this.blockchainModuleManager = ctx.blockchainModuleManager; } - bidSuggestionSchema() { - return bidSuggestionSchema(this.blockchainModuleManager.getImplementationNames()); + async loadSchema(version, schemaName, argumentsObject = {}) { + const schemaPath = path.resolve( + appRootPath.path, + `src/controllers/http-api/${version}/request-schema/${schemaName}-schema-${version}.js`, + ); + const schemaModule = await import(schemaPath); + const schemaFunction = schemaModule.default; + + if (schemaFunction.length !== 0) { + return schemaFunction(argumentsObject); + } + + return schemaFunction(); + } + + async bidSuggestionSchema(version) { + const schemaArgs = {}; + + switch (version) { + case 'v0': + schemaArgs.blockchainImplementationNames = + this.blockchainModuleManager.getImplementationNames(); + break; + default: + throw Error(`HTTP API version: ${version} isn't supported.`); + } + + return this.loadSchema(version, 'bid-suggestion', schemaArgs); } - publishSchema() { - return publishSchema(this.blockchainModuleManager.getImplementationNames()); + async publishSchema(version) { + const schemaArgs = {}; + + switch (version) { + case 'v0': + schemaArgs.blockchainImplementationNames = + this.blockchainModuleManager.getImplementationNames(); + break; + default: + throw Error(`HTTP API version: ${version} isn't supported.`); + } + + return this.loadSchema(version, 'publish', schemaArgs); } - updateSchema() { - return updateSchema(this.blockchainModuleManager.getImplementationNames()); + async updateSchema(version) { + const schemaArgs = {}; + + switch (version) { + case 'v0': + schemaArgs.blockchainImplementationNames = + this.blockchainModuleManager.getImplementationNames(); + break; + default: + throw Error(`HTTP API version: ${version} isn't supported.`); + } + + return this.loadSchema(version, 'update', schemaArgs); } - getSchema() { - return getSchema(); + async getSchema(version) { + const schemaArgs = {}; + + switch (version) { + case 'v0': + break; + default: + throw Error(`HTTP API version: ${version} isn't supported.`); + } + + return this.loadSchema(version, 'get', schemaArgs); } - querySchema() { - return querySchema(); + async querySchema(version) { + const schemaArgs = {}; + + switch (version) { + case 'v0': + break; + default: + throw Error(`HTTP API version: ${version} isn't supported.`); + } + + return this.loadSchema(version, 'query', schemaArgs); } - localStoreSchema() { - return localStoreSchema(this.blockchainModuleManager.getImplementationNames()); + async localStoreSchema(version) { + const schemaArgs = {}; + + switch (version) { + case 'v0': + schemaArgs.blockchainImplementationNames = + this.blockchainModuleManager.getImplementationNames(); + break; + default: + throw Error(`HTTP API version: ${version} isn't supported.`); + } + + return this.loadSchema(version, 'local-store', schemaArgs); } } diff --git a/src/service/pending-storage-service.js b/src/service/pending-storage-service.js index a882ce40af..0817453d27 100644 --- a/src/service/pending-storage-service.js +++ b/src/service/pending-storage-service.js @@ -34,11 +34,11 @@ class PendingStorageService { ); } - async getCachedAssertion(repository, blockchain, contract, tokenId, operationId) { + async getCachedAssertion(repository, blockchain, contract, tokenId, assertionId, operationId) { const ual = this.ualService.deriveUAL(blockchain, contract, tokenId); this.logger.debug( - `Reading cached assertion for ual: ${ual}, operation id: ${operationId} from file in ${repository} pending storage`, + `Reading cached assertion for ual: ${ual}, assertion id: ${assertionId}, operation id: ${operationId} from file in ${repository} pending storage`, ); try { const documentPath = await this.fileService.getPendingStorageDocumentPath( @@ -46,30 +46,57 @@ class PendingStorageService { blockchain, contract, tokenId, + assertionId, ); const data = await this.fileService.readFile(documentPath, true); return data; } catch (error) { - this.logger.debug('Assertion not found in pending storage'); + this.logger.debug( + `Assertion not found in ${repository} pending storage. Error message: ${error.message}, ${error.stackTrace}`, + ); return null; } } - async removeCachedAssertion(repository, blockchain, contract, tokenId, operationId) { + async removeCachedAssertion( + repository, + blockchain, + contract, + tokenId, + assertionId, + operationId, + ) { const ual = this.ualService.deriveUAL(blockchain, contract, tokenId); this.logger.debug( `Removing cached assertion for ual: ${ual} operation id: ${operationId} from file in ${repository} pending storage`, ); - const pendingStorageFolderPath = this.fileService.getPendingStorageFolderPath( + const pendingAssertionPath = await this.fileService.getPendingStorageDocumentPath( repository, blockchain, contract, tokenId, + assertionId, ); - await this.fileService.removeFolder(pendingStorageFolderPath); + await this.fileService.removeFile(pendingAssertionPath); + + const pendingStorageFolderPath = this.fileService.getParentDirectory(pendingAssertionPath); + + try { + const otherPendingAssertions = await this.fileService.readDirectory( + pendingStorageFolderPath, + ); + if (otherPendingAssertions.length === 0) { + await this.fileService.removeFolder(pendingStorageFolderPath); + } + } catch (error) { + this.logger.debug( + `Assertions folder not found in ${repository} pending storage. ` + + `Error message: ${error.message}, ${error.stackTrace}`, + ); + } } async assetHasPendingState(repository, blockchain, contract, tokenId, assertionId) { diff --git a/src/service/sharding-table-service.js b/src/service/sharding-table-service.js index a1200c0deb..87688c0a42 100644 --- a/src/service/sharding-table-service.js +++ b/src/service/sharding-table-service.js @@ -152,6 +152,7 @@ class ShardingTableService { firstAssertionId, hashFunctionId, ) { + const kbSize = assertionSize < BYTES_IN_KILOBYTE ? BYTES_IN_KILOBYTE : assertionSize; const peerRecords = await this.findNeighbourhood( blockchainId, this.blockchainModuleManager.encodePacked( @@ -177,20 +178,13 @@ class ShardingTableService { const r0 = await this.blockchainModuleManager.getR0(blockchainId); - const minBidSuggestion = this.blockchainModuleManager - .toBigNumber(blockchainId, '1') - .mul(epochsNumber) - .mul(r0); - const bidSuggestion = this.blockchainModuleManager .toBigNumber(blockchainId, this.blockchainModuleManager.convertToWei(blockchainId, ask)) - .mul(assertionSize) + .mul(kbSize) .mul(epochsNumber) .mul(r0) .div(BYTES_IN_KILOBYTE); - return bidSuggestion.lte(minBidSuggestion) - ? minBidSuggestion.toString() - : bidSuggestion.toString(); + return bidSuggestion.toString(); } async findEligibleNodes(neighbourhood, bid, r1, r0) { diff --git a/src/service/telemetry-injection-service.js b/src/service/telemetry-injection-service.js deleted file mode 100644 index be59e6ca4f..0000000000 --- a/src/service/telemetry-injection-service.js +++ /dev/null @@ -1,37 +0,0 @@ -class TelemetryInjectionService { - constructor(ctx) { - this.logger = ctx.logger; - this.config = ctx.config; - this.eventEmitter = ctx.eventEmitter; - this.repositoryModuleManager = ctx.repositoryModuleManager; - } - - initialize() { - this.listenOnEvents(); - } - - listenOnEvents() { - this.eventEmitter.on('operation_status_changed', (eventData) => { - this.repositoryModuleManager.createEventRecord( - eventData.operationId, - eventData.lastEvent, - eventData.timestamp, - eventData.value1, - eventData.value2, - eventData.value3, - ); - }); - } - - async getUnpublishedEvents() { - return this.repositoryModuleManager.getUnpublishedEvents(); - } - - async removePublishedEvents(events) { - const ids = events.map((event) => event.id); - - await this.repositoryModuleManager.destroyEvents(ids); - } -} - -export default TelemetryInjectionService; diff --git a/src/service/util/string-util.js b/src/service/util/string-util.js new file mode 100644 index 0000000000..caf2039a70 --- /dev/null +++ b/src/service/util/string-util.js @@ -0,0 +1,13 @@ +class StringUtil { + toCamelCase(str) { + return str.replace(/[-_]+(.)/g, (_, group) => group.toUpperCase()); + } + + capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); + } +} + +const stringUtil = new StringUtil(); + +export default stringUtil; diff --git a/src/service/validation-service.js b/src/service/validation-service.js index a6cd284152..0786db76d0 100644 --- a/src/service/validation-service.js +++ b/src/service/validation-service.js @@ -34,7 +34,6 @@ class ValidationService { this.validateAssertionId(assertion, assertionId); // TODO: get assertion data in one call - await this.validateAssertionSize(blockchain, assertionId, assertion); await this.validateTriplesNumber(blockchain, assertionId, assertion); await this.validateChunkSize(blockchain, assertionId, assertion); @@ -56,7 +55,8 @@ class ValidationService { } const assertionSize = assertionMetadata.getAssertionSizeInBytes(assertion); if (blockchainAssertionSize !== assertionSize) { - throw Error( + // todo after corrective component is implemented, update this logic + this.logger.warn( `Invalid assertion size, value read from blockchain: ${blockchainAssertionSize}, calculated: ${assertionSize}`, ); } @@ -90,7 +90,8 @@ class ValidationService { const calculatedAssertionId = this.validationModuleManager.calculateRoot(assertion); if (assertionId !== calculatedAssertionId) { - throw Error( + // todo after corrective component is implemented, update this logic + this.logger.warn( `Invalid assertion id. Received value: ${assertionId}, calculated: ${calculatedAssertionId}`, ); } diff --git a/test/bdd/features/get.feature b/test/bdd/features/get.feature index d11fcf2f30..88c3af8c01 100644 --- a/test/bdd/features/get.feature +++ b/test/bdd/features/get.feature @@ -59,6 +59,8 @@ Feature: Get asset states test And I wait for latest Update to finalize Then Latest Update operation finished with status: COMPLETED + And I wait for 30 seconds + When I call Update on the node 4 for the latest published UAL with validUpdate_2 And I wait for latest Update to finalize Then Latest Update operation finished with status: COMPLETED diff --git a/test/bdd/steps/lib/local-blockchain.mjs b/test/bdd/steps/lib/local-blockchain.mjs index f9abf86ec8..777238c95d 100644 --- a/test/bdd/steps/lib/local-blockchain.mjs +++ b/test/bdd/steps/lib/local-blockchain.mjs @@ -20,6 +20,7 @@ const testParametersStorageParams = { minProofWindowOffsetPerc: 66, // 4 minutes maxProofWindowOffsetPerc: 66, // 4 minutes proofWindowDurationPerc: 33, // 2 minutes + updateCommitWindowDuration: 60, // 1 minute finalizationCommitsNumber: 3, }; /** diff --git a/test/modules/telemetry/config.json b/test/modules/telemetry/config.json new file mode 100644 index 0000000000..66c5eddea5 --- /dev/null +++ b/test/modules/telemetry/config.json @@ -0,0 +1,17 @@ +{ + "modules": { + "telemetry": { + "enabled": true, + "implementation": { + "ot-telemetry": { + "enabled": true, + "package": "./telemetry/implementation/ot-telemetry.js", + "config": { + "sendTelemetryData": false, + "signalingServerUrl": "null" + } + } + } + } + } +} diff --git a/test/modules/telemetry/telemetry.js b/test/modules/telemetry/telemetry.js new file mode 100644 index 0000000000..6a7c037fa7 --- /dev/null +++ b/test/modules/telemetry/telemetry.js @@ -0,0 +1,51 @@ +import { readFile } from 'fs/promises'; +import { describe, it, before } from 'mocha'; +import { expect, assert } from 'chai'; +import Logger from '../../../src/logger/logger.js'; +import TelemetryModuleManager from '../../../src/modules/telemetry/telemetry-module-manager.js'; + +let logger; +let telemetryModuleManager; +const config = JSON.parse(await readFile('./test/modules/telemetry/config.json')); + +describe('Telemetry module', () => { + before('Initialize logger', () => { + logger = new Logger('trace'); + logger.info = () => {}; + }); + + describe('Handle received events', () => { + it('should call onEventReceived when event is emitted', async () => { + const eventEmitter = { + eventListeners: {}, + + on(eventName, callback) { + if (!this.eventListeners[eventName]) { + this.eventListeners[eventName] = []; + } + this.eventListeners[eventName].push(callback); + }, + + emit(eventName, ...args) { + if (this.eventListeners[eventName]) { + this.eventListeners[eventName].forEach((callback) => callback(...args)); + } + }, + }; + + let callbackCalled = false; + + function onEventReceived() { + callbackCalled = true; + } + + telemetryModuleManager = new TelemetryModuleManager({ config, logger, eventEmitter }); + await telemetryModuleManager.initialize(); + telemetryModuleManager.listenOnEvents(onEventReceived); + + eventEmitter.emit('operation_status_changed'); + + assert(expect(callbackCalled).to.be.true); + }); + }); +}); diff --git a/test/unit/api/http-api-router.test.js b/test/unit/api/http-api-router.test.js new file mode 100644 index 0000000000..0c8e3af4d8 --- /dev/null +++ b/test/unit/api/http-api-router.test.js @@ -0,0 +1,80 @@ +import { beforeEach, describe, it } from 'mocha'; +import { expect } from 'chai'; +import sinon from 'sinon'; +import HttpApiRouter from '../../../src/controllers/http-api/http-api-router.js'; +import JsonSchemaServiceMock from '../mock/json-schema-service-mock.js'; +import HttpClientModuleManagerMock from '../mock/http-client-module-manager-mock.js'; +import { HTTP_API_ROUTES } from '../../../src/constants/constants.js'; + +describe('HTTP API Router test', async () => { + let httpApiRouter; + const controllerMocks = {}; + + beforeEach(() => { + // Mock Controllers + Object.keys(HTTP_API_ROUTES).forEach((version) => { + Object.keys(HTTP_API_ROUTES[version]).forEach((operation) => { + const versionedController = `${operation}HttpApiController${ + version.charAt(1).toUpperCase() + version.slice(2) + }`; + controllerMocks[versionedController] = { handleRequest: sinon.stub() }; + }); + }); + + // Mock context + const ctx = { + httpClientModuleManager: new HttpClientModuleManagerMock(), + jsonSchemaService: new JsonSchemaServiceMock(), + ...controllerMocks, + }; + + // Initialize HttpApiRouter with mocks + httpApiRouter = new HttpApiRouter(ctx); + }); + + it('Router has all defined routes', async () => { + // Extract unique HTTP methods present across all versions + const httpMethods = new Set(); + Object.values(HTTP_API_ROUTES).forEach((routes) => { + Object.values(routes).forEach((route) => { + httpMethods.add(route.method); + }); + }); + + // Create spies for each extracted HTTP method on each router instance and httpClientModuleManager + const spies = {}; + Object.keys(HTTP_API_ROUTES).forEach((version) => { + spies[version] = {}; + Array.from(httpMethods).forEach((method) => { + spies[version][method] = sinon.spy(httpApiRouter.routers[version], method); + }); + }); + const httpClientModuleManagerUseSpy = sinon.spy( + httpApiRouter.httpClientModuleManager, + 'use', + ); + + // Initialize the routes + await httpApiRouter.initialize(); + + // Validate each route + Object.entries(HTTP_API_ROUTES).forEach(([version, routes]) => { + expect(httpClientModuleManagerUseSpy.calledWith(`/${version}`)).to.equal(true); + + Object.values(routes).forEach((routeDetails) => { + const { method, path } = routeDetails; + expect(spies[version][method].calledWith(path)).to.equal(true); + }); + }); + expect(httpClientModuleManagerUseSpy.calledWith('/latest')).to.equal(true); + expect(httpClientModuleManagerUseSpy.calledWith('/')).to.equal(true); + + // Restore all spies + Object.values(spies).forEach((versionSpies) => { + Object.values(versionSpies).forEach((spy) => { + spy.restore(); + }); + }); + httpClientModuleManagerUseSpy.restore(); + }); +}); diff --git a/test/unit/middleware/authentication-middleware.test.js b/test/unit/middleware/authentication-middleware.test.js index cd67d9b888..287af08f03 100644 --- a/test/unit/middleware/authentication-middleware.test.js +++ b/test/unit/middleware/authentication-middleware.test.js @@ -25,7 +25,7 @@ describe('authentication middleware test', async () => { }), ); - const req = { headers: { authorization: 'Bearer token' }, url: '/publish' }; + const req = { headers: { authorization: 'Bearer token' }, path: '/publish' }; const spySend = sandbox.spy(); const spyStatus = sandbox.spy(() => ({ send: spySend })); @@ -46,7 +46,7 @@ describe('authentication middleware test', async () => { }), ); - const req = { headers: { authorization: 'Bearer token' }, url: '/publish' }; + const req = { headers: { authorization: 'Bearer token' }, path: '/publish' }; const spySend = sandbox.spy(); const spyStatus = sandbox.spy(() => ({ send: spySend })); @@ -67,7 +67,7 @@ describe('authentication middleware test', async () => { }), ); - const req = { headers: { authorization: 'Bearer token' }, url: '/publish' }; + const req = { headers: { authorization: 'Bearer token' }, path: '/publish' }; const spySend = sandbox.spy(); const spyStatus = sandbox.spy(() => ({ send: spySend })); diff --git a/test/unit/middleware/authorization-middleware.test.js b/test/unit/middleware/authorization-middleware.test.js index 6d254394f8..6e0dd30714 100644 --- a/test/unit/middleware/authorization-middleware.test.js +++ b/test/unit/middleware/authorization-middleware.test.js @@ -26,7 +26,7 @@ describe('authentication middleware test', async () => { }), ); - const req = { headers: { authorization: 'Bearer token' }, url: '/publish' }; + const req = { headers: { authorization: 'Bearer token' }, path: '/publish' }; const spySend = sandbox.spy(); const spyStatus = sandbox.spy(() => ({ send: spySend })); @@ -46,7 +46,7 @@ describe('authentication middleware test', async () => { }), ); - const req = { headers: { authorization: 'Bearer token' }, url: '/publish' }; + const req = { headers: { authorization: 'Bearer token' }, path: '/publish' }; const spySend = sandbox.spy(); const spyStatus = sandbox.spy(() => ({ send: spySend })); @@ -67,7 +67,7 @@ describe('authentication middleware test', async () => { }), ); - const req = { headers: { authorization: 'Bearer token' }, url: '/publish' }; + const req = { headers: { authorization: 'Bearer token' }, path: '/publish' }; const spySend = sandbox.spy(); const spyStatus = sandbox.spy(() => ({ send: spySend })); diff --git a/test/unit/mock/http-client-module-manager-mock.js b/test/unit/mock/http-client-module-manager-mock.js new file mode 100644 index 0000000000..434fe0fe08 --- /dev/null +++ b/test/unit/mock/http-client-module-manager-mock.js @@ -0,0 +1,21 @@ +import express from 'express'; + +class HttpClientModuleManagerMock { + createRouterInstance() { + return express.Router(); + } + + initializeBeforeMiddlewares() {} + + async listen() {} + + use(path, callback) {} + + selectMiddlewares(options) { + return []; + } + + initializeAfterMiddlewares() {} +} + +export default HttpClientModuleManagerMock; diff --git a/test/unit/mock/json-schema-service-mock.js b/test/unit/mock/json-schema-service-mock.js new file mode 100644 index 0000000000..45e16b0ff7 --- /dev/null +++ b/test/unit/mock/json-schema-service-mock.js @@ -0,0 +1,3 @@ +class JsonSchemaServiceMock {} + +export default JsonSchemaServiceMock; diff --git a/test/unit/service/validation-service.test.js b/test/unit/service/validation-service.test.js index 7cb77e625e..69dafd7e39 100644 --- a/test/unit/service/validation-service.test.js +++ b/test/unit/service/validation-service.test.js @@ -49,22 +49,23 @@ describe('Validation service test', async () => { }); it('Tries to validate assertion but fails due to assertion size mismatch', async () => { - let errorThrown = false; - try { - await validationService.validateAssertion( - '0xde58cc52a5ce3a04ae7a05a13176226447ac02489252e4d37a72cbe0aea46b42', - 'hardhat', - { - '@context': 'https://schema.org', - '@id': 'https://tesla.modelX/2321', - '@type': 'Car', - name: 'Tesla Model X', - }, - ); - } catch (error) { - errorThrown = true; - } - expect(errorThrown).to.be.true; + // todo after corrective component is implemented, update this logic + // let errorThrown = false; + // try { + // await validationService.validateAssertion( + // '0xde58cc52a5ce3a04ae7a05a13176226447ac02489252e4d37a72cbe0aea46b42', + // 'hardhat', + // { + // '@context': 'https://schema.org', + // '@id': 'https://tesla.modelX/2321', + // '@type': 'Car', + // name: 'Tesla Model X', + // }, + // ); + // } catch (error) { + // errorThrown = true; + // } + // expect(errorThrown).to.be.true; }); it('Tries to validate assertion but fails due to triple number mismatch', async () => { @@ -136,34 +137,35 @@ describe('Validation service test', async () => { }); it('Tries to validate assertion but fails due to validation manager returning wrong assertion id', async () => { + // todo after corrective component is implemented, update this logic // Will lead to mismatch with passed assertion id - validationService.validationModuleManager.calculateRoot = (assertion) => ''; - - let errorThrown = false; - try { - await validationService.validateAssertion( - '0xde58cc52a5ce3a04ae7a05a13176226447ac02489252e4d37a72cbe0aea46b42', - 'hardhat', - { - '@context': 'https://schema.org', - '@id': 'https://tesla.modelX/2321', - '@type': 'Car', - name: 'Tesla Model X', - brand: { - '@type': 'Brand', - name: 'Tesla', - }, - model: 'Model X', - manufacturer: { - '@type': 'Organization', - name: 'Tesla, Inc.', - }, - fuelType: 'Electric', - }, - ); - } catch (error) { - errorThrown = true; - } - expect(errorThrown).to.be.true; + // validationService.validationModuleManager.calculateRoot = (assertion) => ''; + // + // let errorThrown = false; + // try { + // await validationService.validateAssertion( + // '0xde58cc52a5ce3a04ae7a05a13176226447ac02489252e4d37a72cbe0aea46b42', + // 'hardhat', + // { + // '@context': 'https://schema.org', + // '@id': 'https://tesla.modelX/2321', + // '@type': 'Car', + // name: 'Tesla Model X', + // brand: { + // '@type': 'Brand', + // name: 'Tesla', + // }, + // model: 'Model X', + // manufacturer: { + // '@type': 'Organization', + // name: 'Tesla, Inc.', + // }, + // fuelType: 'Electric', + // }, + // ); + // } catch (error) { + // errorThrown = true; + // } + // expect(errorThrown).to.be.true; }); });