From 458e4e55764cfd0957c259b2c50c9e42b55ebb07 Mon Sep 17 00:00:00 2001 From: apostolof Date: Sun, 7 Feb 2021 17:51:05 +0200 Subject: [PATCH] refactor: add contracts provider integration to pinner --- .../src/redux/sagas/orbitSaga.js | 4 +- packages/concordia-pinner/package.json | 1 + packages/concordia-pinner/src/index.js | 27 +++++++--- .../src/utils/drizzleUtils.js | 50 +++++++++++++++++++ .../src/constants/configuration/defaults.js | 2 + .../src/environment/interpolated/pinner.js | 5 +- .../src/environment/pinnerEnv.js | 2 + 7 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 packages/concordia-pinner/src/utils/drizzleUtils.js diff --git a/packages/concordia-app/src/redux/sagas/orbitSaga.js b/packages/concordia-app/src/redux/sagas/orbitSaga.js index 1e3a8c4..8852a8e 100644 --- a/packages/concordia-app/src/redux/sagas/orbitSaga.js +++ b/packages/concordia-app/src/redux/sagas/orbitSaga.js @@ -5,9 +5,9 @@ import { import { breezeActions } from '@ezerous/breeze'; import { drizzleActions } from '@ezerous/drizzle'; -import { contracts } from 'concordia-contracts'; import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider'; import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; +import drizzleOptions from '../../options/drizzleOptions'; function* initOrbitDatabases(action) { const { account, breeze } = action; @@ -24,7 +24,7 @@ function* orbitSaga() { const { drizzle: { web3 } } = res[0]; const networkId = yield call([web3.eth.net, web3.eth.net.getId]); - const contractAddress = contracts + const contractAddress = drizzleOptions.contracts .find((contract) => contract.contractName === FORUM_CONTRACT) .networks[networkId].address; diff --git a/packages/concordia-pinner/package.json b/packages/concordia-pinner/package.json index d5b0ccc..964198a 100644 --- a/packages/concordia-pinner/package.json +++ b/packages/concordia-pinner/package.json @@ -32,6 +32,7 @@ "orbit-db": "~0.26.0", "orbit-db-identity-provider": "~0.3.1", "rimraf": "~3.0.2", + "unirest": "^0.6.0", "web3": "~1.3.0", "web3-eth-contract": "^1.3.1", "wrtc": "~0.4.6" diff --git a/packages/concordia-pinner/src/index.js b/packages/concordia-pinner/src/index.js index 401bced..aa5dbb2 100644 --- a/packages/concordia-pinner/src/index.js +++ b/packages/concordia-pinner/src/index.js @@ -7,6 +7,7 @@ import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3'; import { createOrbitInstance, getPeerDatabases, openKVDBs } from './utils/orbitUtils'; import ipfsOptions from './options/ipfsOptions'; import startAPI from './app'; +import downloadContractArtifacts from './utils/drizzleUtils'; process.on('unhandledRejection', (error) => { // This happens when attempting to initialize without any available Swarm addresses (e.g. Rendezvous) @@ -21,16 +22,26 @@ process.on('unhandledRejection', (error) => { }); const getDeployedContract = async (web3) => { - const forumContract = contracts.find((contract) => contract.contractName === FORUM_CONTRACT); + let forumContractPromise; - return web3.eth.net.getId() - .then((networkId) => forumContract.networks[networkId].address) - .then((contractAddress) => { - Contract.setProvider(getWeb3ProviderUrl()); - const contract = new Contract(forumContract.abi, contractAddress); + if (process.env.USE_EXTERNAL_CONTRACTS_PROVIDER) { + console.log('Downloading contracts.'); + forumContractPromise = downloadContractArtifacts() + .then((remoteContracts) => remoteContracts + .find((remoteContract) => remoteContract.contractName === FORUM_CONTRACT)); + } else { + forumContractPromise = Promise.resolve(contracts.find((contract) => contract.contractName === FORUM_CONTRACT)); + } + + return forumContractPromise + .then((forumContract) => web3.eth.net.getId() + .then((networkId) => forumContract.networks[networkId].address) + .then((contractAddress) => { + Contract.setProvider(getWeb3ProviderUrl()); + const contract = new Contract(forumContract.abi, contractAddress); - return { contract, contractAddress }; - }); + return { contract, contractAddress }; + })); }; // Open & replicate databases of existing users diff --git a/packages/concordia-pinner/src/utils/drizzleUtils.js b/packages/concordia-pinner/src/utils/drizzleUtils.js new file mode 100644 index 0000000..028c3e5 --- /dev/null +++ b/packages/concordia-pinner/src/utils/drizzleUtils.js @@ -0,0 +1,50 @@ +import unirest from 'unirest'; +import { + contractsProviderHost, + contractsProviderPort, + contractsVersionHash, +} from 'concordia-shared/src/environment/interpolated/contractsProvider'; +import { pinnerApiHost, pinnerApiPort } from 'concordia-shared/src/environment/interpolated/pinner'; +import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; + +function getContractsDownloadRequest() { + const HOST = pinnerApiHost; + const PORT = pinnerApiPort; + + return unirest( + 'GET', + `http://${contractsProviderHost}:${contractsProviderPort}/contracts/${contractsVersionHash}`, + ).headers({ + 'Access-Control-Allow-Origin': `${HOST}:${PORT}`, + 'Access-Control-Allow-Credentials': 'true', + }); +} + +const validateRemoteContracts = (remoteContracts) => { + if (!remoteContracts + .map((remoteContract) => remoteContract.contractName) + .includes(FORUM_CONTRACT)) { + throw new Error('Forum contract is missing from artifacts.'); + } +}; + +const downloadContractArtifacts = () => { + const request = getContractsDownloadRequest(); + + return new Promise((resolve, reject) => request + .end((response) => { + if (response.error) { + reject(new Error(`Remote contract artifacts download request failed!\n${response.error}`)); + } + + resolve(response.raw_body); + })).then((contractsRawData) => { + const remoteContracts = JSON.parse(contractsRawData); + + validateRemoteContracts(remoteContracts); + + return remoteContracts; + }); +}; + +export default downloadContractArtifacts; diff --git a/packages/concordia-shared/src/constants/configuration/defaults.js b/packages/concordia-shared/src/constants/configuration/defaults.js index 07ee374..6c68265 100644 --- a/packages/concordia-shared/src/constants/configuration/defaults.js +++ b/packages/concordia-shared/src/constants/configuration/defaults.js @@ -4,6 +4,7 @@ const CONTRACTS_PROVIDER_PORT_DEFAULT = '8400'; const CONTRACTS_VERSION_HASH_DEFAULT = 'latest'; // Pinner +const PINNER_API_HOST_DEFAULT = '127.0.0.1'; const PINNER_API_PORT_DEFAULT = 4444; // Rendezvous @@ -25,6 +26,7 @@ module.exports = Object.freeze({ hash: CONTRACTS_VERSION_HASH_DEFAULT, }, pinner: { + host: PINNER_API_HOST_DEFAULT, port: PINNER_API_PORT_DEFAULT, }, rendezvous: { diff --git a/packages/concordia-shared/src/environment/interpolated/pinner.js b/packages/concordia-shared/src/environment/interpolated/pinner.js index 5c81a88..e4007d5 100644 --- a/packages/concordia-shared/src/environment/interpolated/pinner.js +++ b/packages/concordia-shared/src/environment/interpolated/pinner.js @@ -1,12 +1,15 @@ const { pinner: { + host: PINNER_API_HOST_DEFAULT, port: PINNER_API_PORT_DEFAULT, }, } = require('../../constants/configuration/defaults'); -const { pinnerApiPortEnv } = require('../pinnerEnv'); +const { pinnerApiHostEnv, pinnerApiPortEnv } = require('../pinnerEnv'); +const pinnerApiHost = pinnerApiHostEnv || PINNER_API_HOST_DEFAULT; const pinnerApiPort = pinnerApiPortEnv || PINNER_API_PORT_DEFAULT; module.exports = { + pinnerApiHost, pinnerApiPort, }; diff --git a/packages/concordia-shared/src/environment/pinnerEnv.js b/packages/concordia-shared/src/environment/pinnerEnv.js index 2ab5cbf..d1df0bf 100644 --- a/packages/concordia-shared/src/environment/pinnerEnv.js +++ b/packages/concordia-shared/src/environment/pinnerEnv.js @@ -1,7 +1,9 @@ // Depending on the package user (app in contrast to any of the other packages) the env var names should either include // the REACT_APP_ prefix or not +const pinnerApiHostEnv = process.env.REACT_APP_PINNER_API_HOST || process.env.PINNER_API_HOST; const pinnerApiPortEnv = process.env.REACT_APP_PINNER_API_PORT || process.env.PINNER_API_PORT; module.exports = { + pinnerApiHostEnv, pinnerApiPortEnv, };