Compare commits
56 Commits
2.7.0-rc0
...
feature/do
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
052c0738c2 | ||
|
|
03dfaa9bb5 | ||
|
|
e899b15808 | ||
|
|
4eba91ef7e | ||
|
|
1e3aa53ab3 | ||
|
|
a05ff51555 | ||
|
|
52e1c88b58 | ||
|
|
d36dcadd34 | ||
|
|
d543dbb339 | ||
|
|
bd21cc163e | ||
|
|
4a0fc936a1 | ||
|
|
78564afabd | ||
|
|
70a2c30b4c | ||
|
|
06a9586148 | ||
|
|
7379fe4190 | ||
|
|
e59766c5df | ||
|
|
fdb18a1a17 | ||
|
|
4412046f66 | ||
|
|
0ff224ccd3 | ||
|
|
5cedacafe5 | ||
|
|
2e6179f974 | ||
|
|
4f5e3c47be | ||
|
|
4c06329153 | ||
|
|
d53452675e | ||
|
|
c92f80c484 | ||
|
|
5e95b5d8c5 | ||
|
|
6e1f57493a | ||
|
|
8ed6550635 | ||
|
|
c8eb0f1ed8 | ||
|
|
3e5e50c06e | ||
|
|
92e1b597c4 | ||
|
|
8b1a97e673 | ||
|
|
3cf184c391 | ||
|
|
8f72516374 | ||
|
|
98155e3075 | ||
|
|
0d724147bd | ||
|
|
3b959776f3 | ||
|
|
ffbca8b941 | ||
|
|
38f1bae8f5 | ||
|
|
9da1d7ab0a | ||
|
|
78bcd7568b | ||
|
|
429312500a | ||
|
|
59e0bf7565 | ||
|
|
ab51370d5a | ||
|
|
9dfb0510c4 | ||
|
|
f65e8f9244 | ||
|
|
5c8b595382 | ||
|
|
71bf9d5583 | ||
|
|
329ded4beb | ||
|
|
dc70247e2c | ||
|
|
f95beee5dc | ||
|
|
ae83c76be9 | ||
|
|
dc3026e584 | ||
|
|
b6ba0744b9 | ||
|
|
4dba9a50e8 | ||
|
|
818bc4675d |
106
.github/workflows/main.yml
vendored
106
.github/workflows/main.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 12
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 12
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
@@ -61,31 +61,6 @@ jobs:
|
||||
key: ${{ needs.initialize.outputs.cache_key }}
|
||||
- name: yarn run ${{ matrix.task }}
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||
ui-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- initialize
|
||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags')
|
||||
steps:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/cache@v2
|
||||
id: cache-repo
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
contracts/build
|
||||
key: ${{ needs.initialize.outputs.cache_key }}
|
||||
- name: yarn workspace ui run coverage
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && yarn workspace ui run coverage
|
||||
- uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
path-to-lcov: ./ui/coverage/lcov.info
|
||||
build-e2e-images:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -95,21 +70,19 @@ jobs:
|
||||
- name: Evaluate e2e docker images tags
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e', 'e2e-commons') }}" >> $GITHUB_ENV
|
||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
||||
- name: Rebuild and push updated images
|
||||
run: |
|
||||
function check_if_image_exists() {
|
||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||
}
|
||||
updated=()
|
||||
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
|
||||
if ! check_if_image_exists oracle ${ORACLE_TAG}; then updated+=("oracle"); fi
|
||||
if ! check_if_image_exists monitor ${MONITOR_TAG}; then updated+=("monitor"); fi
|
||||
if ! check_if_image_exists ui ${UI_TAG}; then updated+=("ui"); fi
|
||||
if ! check_if_image_exists oracle ${ORACLE_TAG}; then updated+=("oracle-amb"); fi
|
||||
if ! check_if_image_exists monitor ${MONITOR_TAG}; then updated+=("monitor-amb"); fi
|
||||
if ! check_if_image_exists alm ${ALM_TAG}; then updated+=("alm"); fi
|
||||
if [ ${#updated[@]} -gt 0 ]; then
|
||||
echo "Updated services: ${updated[@]}"
|
||||
@@ -131,7 +104,7 @@ jobs:
|
||||
- name: Rebuild and push molecule runner e2e image
|
||||
run: |
|
||||
function check_if_image_exists() {
|
||||
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||
}
|
||||
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
|
||||
echo "Image already exists"
|
||||
@@ -149,12 +122,10 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [oracle-e2e, monitor-e2e, alm-e2e, 'ui-e2e:ci']
|
||||
task: [oracle-e2e, monitor-e2e, alm-e2e]
|
||||
include:
|
||||
- task: alm-e2e
|
||||
use-cache: true
|
||||
- task: 'ui-e2e:ci'
|
||||
use-cache: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -162,10 +133,9 @@ jobs:
|
||||
- name: Evaluate e2e docker images tags
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e', 'e2e-commons') }}" >> $GITHUB_ENV
|
||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
||||
- if: ${{ matrix.use-cache }}
|
||||
uses: actions/cache@v2
|
||||
@@ -179,6 +149,12 @@ jobs:
|
||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- name: yarn run ${{ matrix.task }}
|
||||
run: ${{ !matrix.use-cache || steps.cache-repo.outputs.cache-hit }} && yarn run ${{ matrix.task }}
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: logs-${{ matrix.task }}
|
||||
path: e2e-commons/logs
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
@@ -187,7 +163,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [oracle, ui, monitor, multiple, repo]
|
||||
task: [oracle, monitor, multiple, repo]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -206,20 +182,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [amb, erc-to-erc, erc-to-native, native-to-erc, amb-stake-erc-to-erc]
|
||||
include:
|
||||
- task: erc-to-erc
|
||||
ui-e2e-grep: 'ERC TO ERC'
|
||||
ui-config: 'e2e-commons/components-envs/ui-erc20.env'
|
||||
- task: erc-to-native
|
||||
ui-e2e-grep: 'ERC TO NATIVE'
|
||||
ui-config: 'e2e-commons/components-envs/ui-erc20-native.env'
|
||||
- task: native-to-erc
|
||||
ui-e2e-grep: 'NATIVE TO ERC'
|
||||
ui-config: 'e2e-commons/components-envs/ui.env'
|
||||
- task: amb-stake-erc-to-erc
|
||||
ui-e2e-grep: 'AMB-STAKE-ERC-TO-ERC'
|
||||
ui-config: 'e2e-commons/components-envs/ui-amb-stake-erc20-erc20.env'
|
||||
task: [amb, erc-to-native]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -227,10 +190,9 @@ jobs:
|
||||
- name: Evaluate e2e docker images tags
|
||||
run: |
|
||||
git submodule status > submodule.status
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e') }}" >> $GITHUB_ENV
|
||||
echo "E2E_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'Dockerfile.e2e', 'commons', 'oracle-e2e', 'monitor-e2e', 'e2e-commons') }}" >> $GITHUB_ENV
|
||||
echo "ORACLE_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'oracle') }}" >> $GITHUB_ENV
|
||||
echo "MONITOR_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'monitor') }}" >> $GITHUB_ENV
|
||||
echo "UI_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'ui') }}" >> $GITHUB_ENV
|
||||
echo "ALM_TAG=${{ hashFiles('yarn.lock', 'package.json', 'submodule.status', 'commons', 'alm') }}" >> $GITHUB_ENV
|
||||
echo "MOLECULE_RUNNER_TAG=${{ hashFiles('./deployment-e2e/Dockerfile') }}" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v2
|
||||
@@ -243,29 +205,23 @@ jobs:
|
||||
- name: Login to docker registry
|
||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||
- name: Deploy contracts
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy generate-amb-tx blocks
|
||||
- name: Pull e2e oracle image
|
||||
run: |
|
||||
docker-compose -f ./e2e-commons/docker-compose.yml pull oracle
|
||||
docker-compose -f ./e2e-commons/docker-compose.yml pull oracle-amb
|
||||
docker tag ${DOCKER_IMAGE_BASE}/tokenbridge-e2e-oracle:${ORACLE_TAG} poanetwork/tokenbridge-oracle:latest
|
||||
- if: ${{ matrix.ui-e2e-grep }}
|
||||
name: Pull e2e ui image
|
||||
run: |
|
||||
docker-compose -f ./e2e-commons/docker-compose.yml pull ui
|
||||
docker build \
|
||||
--build-arg DOCKER_IMAGE_BASE=${DOCKER_IMAGE_BASE} \
|
||||
--build-arg UI_TAG=${UI_TAG} \
|
||||
--build-arg DOT_ENV_PATH=${{ matrix.ui-config }} \
|
||||
-f ./e2e-commons/Dockerfile.ui \
|
||||
-t ui_ui:latest \
|
||||
.
|
||||
- name: Deploy oracle and ui
|
||||
- name: Deploy oracle
|
||||
run: deployment-e2e/molecule.sh ultimate-${{ matrix.task }}
|
||||
- name: Reset docker socket permissions
|
||||
run: sudo chown -R $USER:docker /var/run/docker.sock
|
||||
- name: Run ui e2e tests
|
||||
if: ${{ matrix.ui-e2e-grep }}
|
||||
run: cd ui-e2e && xvfb-run yarn mocha -g "${{ matrix.ui-e2e-grep }}" -b ./test.js
|
||||
- name: Run oracle e2e tests
|
||||
if: ${{ !matrix.ui-e2e-grep }}
|
||||
run: docker-compose -f ./e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run ${{ matrix.task }}
|
||||
run: docker-compose -f ./e2e-commons/docker-compose.yml run -e ULTIMATE=true e2e yarn workspace oracle-e2e run ${{ matrix.task }}
|
||||
- name: Save logs
|
||||
if: always()
|
||||
run: e2e-commons/down.sh
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: logs-ultimate-${{ matrix.task }}
|
||||
path: e2e-commons/logs
|
||||
|
||||
@@ -22,7 +22,7 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of th
|
||||
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
ORACLE_BRIDGE_MODE | The bridge mode. The bridge starts listening to a different set of events based on this parameter. | NATIVE_TO_ERC / ERC_TO_ERC / ERC_TO_NATIVE / ARBITRARY_MESSAGE
|
||||
ORACLE_BRIDGE_MODE | The bridge mode. The bridge starts listening to a different set of events based on this parameter. | ERC_TO_NATIVE / ARBITRARY_MESSAGE
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC | **Only use in test environments - must be omitted in production environments.**. If this parameter is specified and set to `yes`, RPC URLs can be specified in form of HTTP links. A warning that the connection is insecure will be written to the logs. | `yes` / `no`
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Home network for new blocks. The interval should match the average production time for a new block. | integer
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL | The interval in milliseconds used to request the RPC node in the Foreign network for new blocks. The interval should match the average production time for a new block. | integer
|
||||
@@ -42,29 +42,19 @@ ORACLE_HOME_TO_FOREIGN_BLOCK_LIST | Filename with a list of addresses, separated
|
||||
ORACLE_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
||||
ORACLE_ALWAYS_RELAY_SIGNATURES | If set to `true`, the oracle will always relay signatures even if it was not the last who finilized the signatures collecting process. The default is `false`. | `true` / `false`
|
||||
ORACLE_RPC_REQUEST_TIMEOUT | Timeout in milliseconds for a single RPC request. Default value is `ORACLE_*_RPC_POLLING_INTERVAL * 2`. | integer
|
||||
|
||||
|
||||
## UI configuration
|
||||
|
||||
name | description | value
|
||||
--- | --- | ---
|
||||
UI_TITLE | The title for the bridge UI page. `%c` will be replaced by the name of the network. | string
|
||||
UI_OG_TITLE | The meta title for the deployed bridge page. | string
|
||||
UI_DESCRIPTION | The meta description for the deployed bridge page. | string
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME | name of the home native coin | string
|
||||
UI_HOME_NETWORK_DISPLAY_NAME | name to be displayed for home network | string
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME | name to be displayed for foreign network | string
|
||||
UI_HOME_WITHOUT_EVENTS | `true` if home network doesn't support events | true/false
|
||||
UI_FOREIGN_WITHOUT_EVENTS | `true` if foreign network doesn't support events | true/false
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE | template link to transaction on home explorer. `%s` will be replaced by transaction hash | URL template
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE | template link to transaction on foreign explorer. `%s` will be replaced by transaction hash | URL template
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE | template link to address on home explorer. `%s` will be replaced by address | URL template
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE | template link to address on foreign explorer. `%s` will be replaced by address | URL template
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Home Bridge contract. | integer
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | An interval in milliseconds used to get the updated gas price value either from the oracle or from the Foreign Bridge contract. | integer
|
||||
UI_PORT | The port for the UI app. | integer
|
||||
UI_STYLES | The set of styles to render the bridge UI page. | core/classic/stake
|
||||
UI_PUBLIC_URL | The public url for the deployed bridge page | string
|
||||
ORACLE_HOME_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resending of stuck transactions for Home sender service. Defaults to 20 minutes. | integer
|
||||
ORACLE_FOREIGN_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resending of stuck transactions for Foreign sender service. Defaults to 20 minutes. | integer
|
||||
ORACLE_SHUTDOWN_SERVICE_URL | Optional external URL to some other service/monitor/configuration manager that controls the remote shutdown process. GET request should return `application/json` message with the following schema: `{ shutdown: true/false }`. | URL
|
||||
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | Optional interval in milliseconds used to request the side RPC node or external shutdown service. Default is 120000. | integer
|
||||
ORACLE_SIDE_RPC_URL | Optional HTTPS URL(s) for communication with the external shutdown service or side RPC nodes, used for shutdown manager activities. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s)
|
||||
ORACLE_FOREIGN_ARCHIVE_RPC_URL | Optional HTTPS URL(s) for communication with the archive nodes on the foreign network. Only used in AMB bridge mode for async information request processing. Several URLs can be specified, delimited by spaces. If the connection to one of these nodes is lost the next URL is used for connection. | URL(s)
|
||||
ORACLE_SHUTDOWN_CONTRACT_ADDRESS | Optional contract address in the side chain accessible through `ORACLE_SIDE_RPC_URL`, where the method passed in `ORACLE_SHUTDOWN_CONTRACT_METHOD` is implemented. | `address`
|
||||
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
|
||||
ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer`
|
||||
ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer`
|
||||
ORACLE_JSONRPC_ERROR_CODES | Override default JSON rpc error codes that can trigger RPC fallback to the next URL from the list (or a retry in case of a single RPC URL). Default is `-32603,-32002,-32005`. Should be a comma-separated list of negative integers. | `string`
|
||||
ORACLE_VALIDATOR_KEYSTORE_PATH | Path to the keystore v3 json file with the encrypted validator key. | `string`
|
||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD | Password from the provided keystore file, oracle won't startup properly, if the provided password is invalid | `string`
|
||||
|
||||
|
||||
## Monitor configuration
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:10 as contracts
|
||||
FROM node:12 as contracts
|
||||
|
||||
WORKDIR /mono
|
||||
|
||||
@@ -11,7 +11,7 @@ COPY ./contracts/truffle-config.js ./
|
||||
COPY ./contracts/contracts ./contracts
|
||||
RUN npm run compile
|
||||
|
||||
FROM node:10
|
||||
FROM node:12
|
||||
|
||||
WORKDIR /mono
|
||||
COPY package.json .
|
||||
@@ -19,6 +19,7 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
|
||||
COPY commons/package.json ./commons/
|
||||
COPY oracle-e2e/package.json ./oracle-e2e/
|
||||
COPY monitor-e2e/package.json ./monitor-e2e/
|
||||
COPY oracle/src/utils/constants.js ./oracle/src/utils/constants.js
|
||||
|
||||
COPY yarn.lock .
|
||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
||||
|
||||
@@ -20,12 +20,10 @@ Sub-repositories maintained within this monorepo are listed below.
|
||||
| Sub-repository | Description |
|
||||
| --- | --- |
|
||||
| [Oracle](oracle/README.md) | Oracle responsible for listening to bridge related events and authorizing asset transfers. |
|
||||
| [UI](ui/README.md) | DApp interface to transfer tokens and coins between chains. |
|
||||
| [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. |
|
||||
| [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. |
|
||||
| [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle |
|
||||
| [Monitor-E2E](monitor-e2e/README.md) | End to end tests for the Monitor |
|
||||
| [UI-E2E](ui-e2e/README.md) | End to end tests for the UI |
|
||||
| [Deployment-E2E](deployment-e2e/README.md) | End to end tests for the Deployment |
|
||||
| [Commons](commons/README.md) | Interfaces, constants and utilities shared between the sub-repositories |
|
||||
| [E2E-Commons](e2e-commons/README.md) | Common utilities and configuration used in end to end tests |
|
||||
@@ -56,8 +54,6 @@ Additionally there are [Smart Contracts](https://github.com/poanetwork/tokenbrid
|
||||
|
||||
The POA TokenBridge provides four operational modes:
|
||||
|
||||
- [x] `Native-to-ERC20` **Coins** on a Home network can be converted to ERC20-compatible **tokens** on a Foreign network. Coins are locked on the Home side and the corresponding amount of ERC20 tokens are minted on the Foreign side. When the operation is reversed, tokens are burnt on the Foreign side and unlocked in the Home network. **More Information: [POA-to-POA20 Bridge](https://medium.com/poa-network/introducing-poa-bridge-and-poa20-55d8b78058ac)**
|
||||
- [x] `ERC20-to-ERC20` ERC20-compatible tokens on the Foreign network are locked and minted as ERC20-compatible tokens (ERC677 tokens) on the Home network. When transferred from Home to Foreign, they are burnt on the Home side and unlocked in the Foreign network. This can be considered a form of atomic swap when a user swaps the token "X" in network "A" to the token "Y" in network "B". **More Information: [ERC20-to-ERC20](https://medium.com/poa-network/introducing-the-erc20-to-erc20-tokenbridge-ce266cc1a2d0)**
|
||||
- [x] `ERC20-to-Native`: Pre-existing **tokens** in the Foreign network are locked and **coins** are minted in the `Home` network. In this mode, the Home network consensus engine invokes [Parity's Block Reward contract](https://wiki.parity.io/Block-Reward-Contract.html) to mint coins per the bridge contract request. **More Information: [xDai Chain](https://medium.com/poa-network/poa-network-partners-with-makerdao-on-xdai-chain-the-first-ever-usd-stable-blockchain-65a078c41e6a)**
|
||||
- [x] `Arbitrary-Message`: Transfer arbitrary data between two networks as so the data could be interpreted as an arbitrary contract method invocation.
|
||||
|
||||
@@ -68,7 +64,7 @@ Clone the repository:
|
||||
git clone https://github.com/poanetwork/tokenbridge
|
||||
```
|
||||
|
||||
If there is no need to build docker images for the TokenBridge components (oracle, monitor, UI), initialize submodules, install dependencies, compile the Smart Contracts:
|
||||
If there is no need to build docker images for the TokenBridge components (oracle, monitor), initialize submodules, install dependencies, compile the Smart Contracts:
|
||||
```
|
||||
yarn initialize
|
||||
```
|
||||
@@ -91,7 +87,7 @@ Running tests for all projects:
|
||||
yarn test
|
||||
```
|
||||
|
||||
Additionally there are end-to-end tests for [Oracle](oracle-e2e/README.md) and [UI](ui-e2e/README.md).
|
||||
Additionally there are end-to-end tests for [Oracle](oracle-e2e/README.md) and [Monitor](monitor-e2e/README.md).
|
||||
|
||||
For details on building, running and developing please refer to respective READMEs in sub-repositories.
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"eslint-plugin-jest": "^23.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.18"
|
||||
"node": ">= 12.22"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
cd $(dirname $0)
|
||||
|
||||
../e2e-commons/up.sh deploy blocks alm alm-e2e
|
||||
../e2e-commons/up.sh deploy generate-amb-tx blocks alm alm-e2e
|
||||
|
||||
# run oracle amb e2e tests to generate transactions for alm
|
||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm
|
||||
|
||||
@@ -6,8 +6,8 @@ jest.setTimeout(60000)
|
||||
const statusText = 'Success'
|
||||
const statusSelector = 'label[data-id="status"]'
|
||||
|
||||
const homeToForeignTxURL = 'http://localhost:3004/77/0x58e7d63368335b9591d4dbb43889084f698fcee93ab7656fd7a39d8c66bc4b60'
|
||||
const foreignToHomeTxURL = 'http://localhost:3004/42/0x592bf28fc896419d2838f71cd0388775814b692688f1ecd5b1519081566b994a'
|
||||
const homeToForeignTxURL = 'http://localhost:3004/77/0x295efbe6ae98937ef35d939376c9bd752b4dc6f6899a9d5ddd6a57cea3d76c89'
|
||||
const foreignToHomeTxURL = 'http://localhost:3004/42/0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd'
|
||||
|
||||
describe('ALM', () => {
|
||||
let browser
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:10 as contracts
|
||||
FROM node:12 as contracts
|
||||
|
||||
WORKDIR /mono
|
||||
|
||||
@@ -19,7 +19,7 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
|
||||
COPY commons/package.json ./commons/
|
||||
COPY alm/package.json ./alm/
|
||||
COPY yarn.lock .
|
||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile
|
||||
|
||||
COPY ./commons ./commons
|
||||
COPY ./alm ./alm
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-plugin-prettier": "^3.1.3"
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ const { BRIDGE_VALIDATORS_ABI, HOME_AMB_ABI } = require('commons')
|
||||
const path = require('path')
|
||||
require('dotenv').config()
|
||||
const Web3 = require('web3')
|
||||
const fetch = require('node-fetch')
|
||||
const { URL } = require('url')
|
||||
|
||||
const fs = require('fs')
|
||||
|
||||
@@ -10,7 +12,9 @@ const {
|
||||
COMMON_HOME_RPC_URL,
|
||||
COMMON_HOME_BRIDGE_ADDRESS,
|
||||
COMMON_FOREIGN_RPC_URL,
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||
ALM_FOREIGN_EXPLORER_API,
|
||||
ALM_HOME_EXPLORER_API
|
||||
} = process.env
|
||||
|
||||
const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||
@@ -19,6 +23,31 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||
const snapshot = {}
|
||||
|
||||
const web3 = new Web3(new Web3.providers.HttpProvider(url))
|
||||
const api = side === 'home' ? ALM_HOME_EXPLORER_API : ALM_FOREIGN_EXPLORER_API
|
||||
|
||||
const getPastEventsWithFallback = (contract, eventName, options) =>
|
||||
contract.getPastEvents(eventName, options).catch(async e => {
|
||||
if (e.message.includes('exceed maximum block range')) {
|
||||
const abi = contract.options.jsonInterface.find(abi => abi.type === 'event' && abi.name === eventName)
|
||||
|
||||
const url = new URL(api)
|
||||
url.searchParams.append('module', 'logs')
|
||||
url.searchParams.append('action', 'getLogs')
|
||||
url.searchParams.append('address', contract.options.address)
|
||||
url.searchParams.append('fromBlock', options.fromBlock)
|
||||
url.searchParams.append('toBlock', options.toBlock || 'latest')
|
||||
url.searchParams.append('topic0', web3.eth.abi.encodeEventSignature(abi))
|
||||
|
||||
const logs = await fetch(url).then(res => res.json())
|
||||
|
||||
return logs.result.map(log => ({
|
||||
transactionHash: log.transactionHash,
|
||||
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
||||
returnValues: web3.eth.abi.decodeLog(abi.inputs, log.data, log.topics.slice(1))
|
||||
}))
|
||||
}
|
||||
throw e
|
||||
})
|
||||
|
||||
const currentBlockNumber = await web3.eth.getBlockNumber()
|
||||
snapshot.snapshotBlockNumber = currentBlockNumber
|
||||
@@ -29,10 +58,14 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||
const bridgeContract = new web3.eth.Contract(HOME_AMB_ABI, bridgeAddress)
|
||||
|
||||
// Save RequiredBlockConfirmationChanged events
|
||||
let requiredBlockConfirmationChangedEvents = await bridgeContract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||
fromBlock: 0,
|
||||
toBlock: currentBlockNumber
|
||||
})
|
||||
let requiredBlockConfirmationChangedEvents = await getPastEventsWithFallback(
|
||||
bridgeContract,
|
||||
'RequiredBlockConfirmationChanged',
|
||||
{
|
||||
fromBlock: 0,
|
||||
toBlock: currentBlockNumber
|
||||
}
|
||||
)
|
||||
|
||||
// In case RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
|
||||
// manually generate an event for this. Example Sokol - Kovan bridge
|
||||
@@ -59,10 +92,14 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
||||
|
||||
// Save RequiredSignaturesChanged events
|
||||
const RequiredSignaturesChangedEvents = await validatorContract.getPastEvents('RequiredSignaturesChanged', {
|
||||
fromBlock: 0,
|
||||
toBlock: currentBlockNumber
|
||||
})
|
||||
const RequiredSignaturesChangedEvents = await getPastEventsWithFallback(
|
||||
validatorContract,
|
||||
'RequiredSignaturesChanged',
|
||||
{
|
||||
fromBlock: 0,
|
||||
toBlock: currentBlockNumber
|
||||
}
|
||||
)
|
||||
snapshot.RequiredSignaturesChanged = RequiredSignaturesChangedEvents.map(e => ({
|
||||
blockNumber: e.blockNumber,
|
||||
returnValues: {
|
||||
@@ -71,7 +108,7 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||
}))
|
||||
|
||||
// Save ValidatorAdded events
|
||||
const validatorAddedEvents = await validatorContract.getPastEvents('ValidatorAdded', {
|
||||
const validatorAddedEvents = await getPastEventsWithFallback(validatorContract, 'ValidatorAdded', {
|
||||
fromBlock: 0,
|
||||
toBlock: currentBlockNumber
|
||||
})
|
||||
@@ -85,7 +122,7 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||
}))
|
||||
|
||||
// Save ValidatorRemoved events
|
||||
const validatorRemovedEvents = await validatorContract.getPastEvents('ValidatorRemoved', {
|
||||
const validatorRemovedEvents = await getPastEventsWithFallback(validatorContract, 'ValidatorRemoved', {
|
||||
fromBlock: 0,
|
||||
toBlock: currentBlockNumber
|
||||
})
|
||||
|
||||
@@ -123,6 +123,24 @@ const abi: AbiItem[] = [
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [
|
||||
{
|
||||
name: '_data',
|
||||
type: 'bytes'
|
||||
},
|
||||
{
|
||||
name: '_signatures',
|
||||
type: 'bytes'
|
||||
}
|
||||
],
|
||||
name: 'safeExecuteSignaturesWithAutoGasLimit',
|
||||
outputs: [],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
||||
import { useWindowWidth } from '@react-hook/window-size'
|
||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
||||
@@ -9,6 +9,7 @@ import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||
import { ManualExecutionButton } from './ManualExecutionButton'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
|
||||
const StyledExecutionConfirmation = styled.div`
|
||||
margin-top: 30px;
|
||||
@@ -33,6 +34,8 @@ export const ExecutionConfirmation = ({
|
||||
executionEventsFetched,
|
||||
setPendingExecution
|
||||
}: ExecutionConfirmationParams) => {
|
||||
const { foreign } = useStateProvider()
|
||||
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
|
||||
const availableManualExecution =
|
||||
!isHome &&
|
||||
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
|
||||
@@ -48,6 +51,22 @@ export const ExecutionConfirmation = ({
|
||||
const formattedValidator =
|
||||
windowWidth < 850 && executionData.validator ? formatTxHash(executionData.validator) : executionData.validator
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!availableManualExecution || !foreign.bridgeContract) return
|
||||
|
||||
const p = foreign.bridgeContract.methods.getBridgeInterfacesVersion().call()
|
||||
p.then(({ major, minor }: any) => {
|
||||
major = parseInt(major, 10)
|
||||
minor = parseInt(minor, 10)
|
||||
if (major < 5 || (major === 5 && minor < 7)) return
|
||||
|
||||
setSafeExecutionAvailable(true)
|
||||
})
|
||||
},
|
||||
[availableManualExecution, foreign.bridgeContract]
|
||||
)
|
||||
|
||||
const getExecutionStatusElement = (validatorStatus = '') => {
|
||||
switch (validatorStatus) {
|
||||
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
|
||||
@@ -105,6 +124,7 @@ export const ExecutionConfirmation = ({
|
||||
{availableManualExecution && (
|
||||
<td>
|
||||
<ManualExecutionButton
|
||||
safeExecutionAvailable={safeExecutionAvailable}
|
||||
messageData={messageData}
|
||||
setExecutionData={setExecutionData}
|
||||
signatureCollected={signatureCollected as string[]}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
DOUBLE_EXECUTION_ATTEMPT_ERROR,
|
||||
EXECUTION_FAILED_ERROR,
|
||||
EXECUTION_OUT_OF_GAS_ERROR,
|
||||
FOREIGN_EXPLORER_API,
|
||||
INCORRECT_CHAIN_ERROR,
|
||||
VALIDATOR_CONFIRMATION_STATUS
|
||||
} from '../config/constants'
|
||||
@@ -14,16 +15,19 @@ import { signatureToVRS, packSignatures } from '../utils/signatures'
|
||||
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
||||
import { TransactionReceipt } from 'web3-eth'
|
||||
|
||||
const StyledButton = styled.button`
|
||||
const ActionButton = styled.button`
|
||||
color: var(--button-color);
|
||||
border-color: var(--font-color);
|
||||
margin-top: 10px;
|
||||
min-width: 120px;
|
||||
padding: 1rem;
|
||||
&:focus {
|
||||
outline: var(--button-color);
|
||||
}
|
||||
`
|
||||
|
||||
interface ManualExecutionButtonParams {
|
||||
safeExecutionAvailable: boolean
|
||||
messageData: string
|
||||
setExecutionData: Function
|
||||
signatureCollected: string[]
|
||||
@@ -31,6 +35,7 @@ interface ManualExecutionButtonParams {
|
||||
}
|
||||
|
||||
export const ManualExecutionButton = ({
|
||||
safeExecutionAvailable,
|
||||
messageData,
|
||||
setExecutionData,
|
||||
signatureCollected,
|
||||
@@ -39,6 +44,8 @@ export const ManualExecutionButton = ({
|
||||
const { foreign, setError } = useStateProvider()
|
||||
const { library, activate, account, active } = useWeb3React()
|
||||
const [manualExecution, setManualExecution] = useState(false)
|
||||
const [allowFailures, setAllowFailures] = useState(false)
|
||||
const notReady = !foreign.bridgeContract || !signatureCollected || !signatureCollected.length
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
@@ -71,7 +78,11 @@ export const ManualExecutionButton = ({
|
||||
const signatures = packSignatures(signatureCollected.map(signatureToVRS))
|
||||
const messageId = messageData.slice(0, 66)
|
||||
const bridge = foreign.bridgeContract
|
||||
const data = bridge.methods.executeSignatures(messageData, signatures).encodeABI()
|
||||
const executeMethod =
|
||||
safeExecutionAvailable && !allowFailures
|
||||
? bridge.methods.safeExecuteSignaturesWithAutoGasLimit
|
||||
: bridge.methods.executeSignatures
|
||||
const data = executeMethod(messageData, signatures).encodeABI()
|
||||
setManualExecution(false)
|
||||
|
||||
library.eth
|
||||
@@ -92,7 +103,13 @@ export const ManualExecutionButton = ({
|
||||
})
|
||||
.on('error', async (e: Error, receipt: TransactionReceipt) => {
|
||||
if (e.message.includes('Transaction has been reverted by the EVM')) {
|
||||
const successExecutionData = await getSuccessExecutionData(bridge, 'RelayedMessage', library, messageId)
|
||||
const successExecutionData = await getSuccessExecutionData(
|
||||
bridge,
|
||||
'RelayedMessage',
|
||||
library,
|
||||
messageId,
|
||||
FOREIGN_EXPLORER_API
|
||||
)
|
||||
if (successExecutionData) {
|
||||
setExecutionData(successExecutionData)
|
||||
setError(DOUBLE_EXECUTION_ATTEMPT_ERROR)
|
||||
@@ -125,15 +142,35 @@ export const ManualExecutionButton = ({
|
||||
messageData,
|
||||
signatureCollected,
|
||||
setExecutionData,
|
||||
setPendingExecution
|
||||
setPendingExecution,
|
||||
safeExecutionAvailable,
|
||||
allowFailures
|
||||
]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="is-center">
|
||||
<StyledButton className="button outline" onClick={() => setManualExecution(true)}>
|
||||
Execute
|
||||
</StyledButton>
|
||||
<div>
|
||||
<div className="is-center">
|
||||
<ActionButton disabled={notReady} className="button outline" onClick={() => setManualExecution(true)}>
|
||||
Execute
|
||||
</ActionButton>
|
||||
</div>
|
||||
{safeExecutionAvailable && (
|
||||
<div
|
||||
title="Allow executed message to fail and record its failure on-chain without reverting the whole transaction.
|
||||
Use fixed gas limit for execution."
|
||||
className="is-center"
|
||||
style={{ paddingTop: 10 }}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="allow-failures"
|
||||
checked={allowFailures}
|
||||
onChange={e => setAllowFailures(e.target.checked)}
|
||||
/>
|
||||
<label htmlFor="allow-failures">Unsafe mode</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import { useStateProvider } from '../state/StateProvider'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import { getRequiredBlockConfirmations } from '../utils/contract'
|
||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||
import Web3 from 'web3'
|
||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
||||
|
||||
export interface UseBlockConfirmationsParams {
|
||||
fromHome: boolean
|
||||
@@ -19,9 +21,11 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
||||
contract: Contract,
|
||||
receipt: TransactionReceipt,
|
||||
setResult: Function,
|
||||
snapshotProvider: SnapshotProvider
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3,
|
||||
api: string
|
||||
) => {
|
||||
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider)
|
||||
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
@@ -29,10 +33,12 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
||||
() => {
|
||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
if (!bridgeContract || !receipt) return
|
||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider)
|
||||
const web3 = fromHome ? home.web3 : foreign.web3
|
||||
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||
if (!bridgeContract || !receipt || !web3) return
|
||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider, web3, api)
|
||||
},
|
||||
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
|
||||
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome, home.web3, foreign.web3]
|
||||
)
|
||||
|
||||
return {
|
||||
|
||||
@@ -11,9 +11,6 @@ import {
|
||||
VALIDATOR_CONFIRMATION_STATUS
|
||||
} from '../config/constants'
|
||||
import { homeBlockNumberProvider, foreignBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||
import { checkSignaturesWaitingForBLocks } from '../utils/signatureWaitingForBlocks'
|
||||
import { getCollectedSignaturesEvent } from '../utils/getCollectedSignaturesEvent'
|
||||
import { checkWaitingBlocksForExecution } from '../utils/executionWaitingForBlocks'
|
||||
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
|
||||
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
|
||||
import {
|
||||
@@ -64,11 +61,11 @@ export const useMessageConfirmations = ({
|
||||
blockConfirmations
|
||||
}: useMessageConfirmationsParams) => {
|
||||
const { home, foreign } = useStateProvider()
|
||||
const [confirmations, setConfirmations] = useState([])
|
||||
const [confirmations, setConfirmations] = useState<ConfirmationParam[]>([])
|
||||
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
|
||||
const [waitingBlocks, setWaitingBlocks] = useState(false)
|
||||
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
|
||||
const [signatureCollected, setSignatureCollected] = useState(false)
|
||||
const [signatureCollected, setSignatureCollected] = useState<boolean | string[]>(false)
|
||||
const [executionEventsFetched, setExecutionEventsFetched] = useState(false)
|
||||
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
|
||||
const [executionData, setExecutionData] = useState<ExecutionData>({
|
||||
@@ -85,12 +82,10 @@ export const useMessageConfirmations = ({
|
||||
const [pendingConfirmations, setPendingConfirmations] = useState(false)
|
||||
const [pendingExecution, setPendingExecution] = useState(false)
|
||||
|
||||
const existsConfirmation = (confirmationArray: ConfirmationParam[]) => {
|
||||
const filteredList = confirmationArray.filter(
|
||||
const existsConfirmation = (confirmationArray: ConfirmationParam[]) =>
|
||||
confirmationArray.some(
|
||||
c => c.status !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED && c.status !== VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
)
|
||||
return filteredList.length > 0
|
||||
}
|
||||
|
||||
// start watching blocks at the start
|
||||
useEffect(
|
||||
@@ -108,129 +103,154 @@ export const useMessageConfirmations = ({
|
||||
() => {
|
||||
if (!receipt || !blockConfirmations || waitingBlocksResolved) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
let timeoutId: number
|
||||
|
||||
const blockProvider = fromHome ? homeBlockNumberProvider : foreignBlockNumberProvider
|
||||
const interval = fromHome ? HOME_RPC_POLLING_INTERVAL : FOREIGN_RPC_POLLING_INTERVAL
|
||||
const targetBlock = receipt.blockNumber + blockConfirmations
|
||||
const validatorsWaiting = validatorList.map(validator => ({
|
||||
validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
|
||||
checkSignaturesWaitingForBLocks(
|
||||
targetBlock,
|
||||
setWaitingBlocks,
|
||||
setWaitingBlocksResolved,
|
||||
validatorList,
|
||||
setConfirmations,
|
||||
blockProvider,
|
||||
interval,
|
||||
subscriptions
|
||||
)
|
||||
const checkSignaturesWaitingForBLocks = () => {
|
||||
const currentBlock = blockProvider.get()
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
if (currentBlock && currentBlock >= targetBlock) {
|
||||
setWaitingBlocksResolved(true)
|
||||
setWaitingBlocks(false)
|
||||
} else if (currentBlock) {
|
||||
setWaitingBlocks(true)
|
||||
setConfirmations(validatorsWaiting)
|
||||
timeoutId = setTimeout(checkSignaturesWaitingForBLocks, interval)
|
||||
} else {
|
||||
timeoutId = setTimeout(checkSignaturesWaitingForBLocks, 500)
|
||||
}
|
||||
}
|
||||
|
||||
checkSignaturesWaitingForBLocks()
|
||||
|
||||
return () => clearTimeout(timeoutId)
|
||||
},
|
||||
[
|
||||
blockConfirmations,
|
||||
foreign.web3,
|
||||
fromHome,
|
||||
validatorList,
|
||||
home.web3,
|
||||
receipt,
|
||||
setConfirmations,
|
||||
waitingBlocksResolved
|
||||
]
|
||||
[blockConfirmations, fromHome, receipt, validatorList, waitingBlocksResolved]
|
||||
)
|
||||
|
||||
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
|
||||
// the execution tx on the foreign network is waiting for block confirmations
|
||||
// This is executed if the message is in Home to Foreign direction only
|
||||
const hasCollectedSignatures = !!signatureCollected // true or string[]
|
||||
useEffect(
|
||||
() => {
|
||||
if (!fromHome || !receipt || !home.web3 || !signatureCollected) return
|
||||
if (!fromHome || !receipt || !home.web3 || !home.bridgeContract || !hasCollectedSignatures) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
let timeoutId: number
|
||||
let isCancelled = false
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
|
||||
const contract = home.bridgeContract
|
||||
|
||||
const getCollectedSignaturesEvent = async (fromBlock: number, toBlock: number) => {
|
||||
const currentBlock = homeBlockNumberProvider.get()
|
||||
|
||||
if (currentBlock) {
|
||||
// prevent errors if the toBlock parameter is bigger than the latest
|
||||
const securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
|
||||
const events = await contract.getPastEvents('CollectedSignatures', {
|
||||
fromBlock,
|
||||
toBlock: securedToBlock
|
||||
})
|
||||
const event = events.find(e => e.returnValues.messageHash === messageHash)
|
||||
if (event) {
|
||||
setCollectedSignaturesEvent(event)
|
||||
} else if (!isCancelled) {
|
||||
timeoutId = setTimeout(() => getCollectedSignaturesEvent(securedToBlock, securedToBlock + BLOCK_RANGE), 500)
|
||||
}
|
||||
} else if (!isCancelled) {
|
||||
timeoutId = setTimeout(() => getCollectedSignaturesEvent(fromBlock, toBlock), 500)
|
||||
}
|
||||
}
|
||||
|
||||
const fromBlock = receipt.blockNumber
|
||||
const toBlock = fromBlock + BLOCK_RANGE
|
||||
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
|
||||
|
||||
getCollectedSignaturesEvent(
|
||||
home.web3,
|
||||
home.bridgeContract,
|
||||
fromBlock,
|
||||
toBlock,
|
||||
messageHash,
|
||||
setCollectedSignaturesEvent,
|
||||
subscriptions
|
||||
)
|
||||
getCollectedSignaturesEvent(receipt.blockNumber, receipt.blockNumber + BLOCK_RANGE)
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
clearTimeout(timeoutId)
|
||||
isCancelled = true
|
||||
}
|
||||
},
|
||||
[fromHome, home.bridgeContract, home.web3, message.data, receipt, signatureCollected]
|
||||
[fromHome, home.bridgeContract, home.web3, message.data, receipt, hasCollectedSignatures]
|
||||
)
|
||||
|
||||
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
|
||||
// This is executed if the message is in Home to Foreign direction only
|
||||
useEffect(
|
||||
() => {
|
||||
if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return
|
||||
if (!fromHome || !home.web3 || !collectedSignaturesEvent || !blockConfirmations) return
|
||||
if (waitingBlocksForExecutionResolved) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
let timeoutId: number
|
||||
|
||||
const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations
|
||||
|
||||
checkWaitingBlocksForExecution(
|
||||
homeBlockNumberProvider,
|
||||
HOME_RPC_POLLING_INTERVAL,
|
||||
targetBlock,
|
||||
collectedSignaturesEvent,
|
||||
setWaitingBlocksForExecution,
|
||||
setWaitingBlocksForExecutionResolved,
|
||||
setExecutionData,
|
||||
subscriptions
|
||||
)
|
||||
const checkWaitingBlocksForExecution = () => {
|
||||
const currentBlock = homeBlockNumberProvider.get()
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
if (currentBlock && currentBlock >= targetBlock) {
|
||||
const undefinedExecutionState = {
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||
txHash: '',
|
||||
timestamp: 0,
|
||||
executionResult: false
|
||||
}
|
||||
setExecutionData(
|
||||
(data: any) =>
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
? undefinedExecutionState
|
||||
: data
|
||||
)
|
||||
setWaitingBlocksForExecutionResolved(true)
|
||||
setWaitingBlocksForExecution(false)
|
||||
} else if (currentBlock) {
|
||||
setWaitingBlocksForExecution(true)
|
||||
const waitingExecutionState = {
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||
txHash: '',
|
||||
timestamp: 0,
|
||||
executionResult: false
|
||||
}
|
||||
setExecutionData(
|
||||
(data: any) =>
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
? waitingExecutionState
|
||||
: data
|
||||
)
|
||||
timeoutId = setTimeout(() => checkWaitingBlocksForExecution(), HOME_RPC_POLLING_INTERVAL)
|
||||
} else {
|
||||
timeoutId = setTimeout(() => checkWaitingBlocksForExecution(), 500)
|
||||
}
|
||||
}
|
||||
|
||||
checkWaitingBlocksForExecution()
|
||||
|
||||
return () => clearTimeout(timeoutId)
|
||||
},
|
||||
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt, waitingBlocksForExecutionResolved]
|
||||
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, waitingBlocksForExecutionResolved]
|
||||
)
|
||||
|
||||
// Checks if validators verified the message
|
||||
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
|
||||
useEffect(
|
||||
() => {
|
||||
if (!waitingBlocksResolved || !homeStartBlock || !requiredSignatures) return
|
||||
if (!waitingBlocksResolved || !homeStartBlock || !requiredSignatures || !home.web3 || !home.bridgeContract) return
|
||||
if (!validatorList || !validatorList.length) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
let timeoutId: number
|
||||
let isCancelled = false
|
||||
|
||||
getConfirmationsForTx(
|
||||
message.data,
|
||||
@@ -241,8 +261,8 @@ export const useMessageConfirmations = ({
|
||||
setConfirmations,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
id => (timeoutId = id),
|
||||
() => isCancelled,
|
||||
homeStartBlock,
|
||||
getValidatorFailedTransactionsForMessage,
|
||||
setFailedConfirmations,
|
||||
@@ -252,7 +272,8 @@ export const useMessageConfirmations = ({
|
||||
)
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
clearTimeout(timeoutId)
|
||||
isCancelled = true
|
||||
}
|
||||
},
|
||||
[
|
||||
@@ -263,8 +284,7 @@ export const useMessageConfirmations = ({
|
||||
home.bridgeContract,
|
||||
requiredSignatures,
|
||||
waitingBlocksResolved,
|
||||
homeStartBlock,
|
||||
setConfirmations
|
||||
homeStartBlock
|
||||
]
|
||||
)
|
||||
|
||||
@@ -274,32 +294,23 @@ export const useMessageConfirmations = ({
|
||||
useEffect(
|
||||
() => {
|
||||
if ((fromHome && !waitingBlocksForExecutionResolved) || (!fromHome && !waitingBlocksResolved)) return
|
||||
const startBlock = fromHome ? foreignStartBlock : homeStartBlock
|
||||
if (!startBlock) return
|
||||
|
||||
const subscriptions: Array<number> = []
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
|
||||
const contractEvent = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
|
||||
const bridgeContract = fromHome ? foreign.bridgeContract : home.bridgeContract
|
||||
const providedWeb3 = fromHome ? foreign.web3 : home.web3
|
||||
const interval = fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
|
||||
const web3 = fromHome ? foreign.web3 : home.web3
|
||||
const startBlock = fromHome ? foreignStartBlock : homeStartBlock
|
||||
if (!startBlock || !bridgeContract || !web3) return
|
||||
|
||||
let timeoutId: number
|
||||
let isCancelled = false
|
||||
|
||||
getFinalizationEvent(
|
||||
fromHome,
|
||||
bridgeContract,
|
||||
contractEvent,
|
||||
providedWeb3,
|
||||
web3,
|
||||
setExecutionData,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
id => (timeoutId = id),
|
||||
() => isCancelled,
|
||||
startBlock,
|
||||
collectedSignaturesEvent,
|
||||
getExecutionFailedTransactionForMessage,
|
||||
@@ -310,7 +321,8 @@ export const useMessageConfirmations = ({
|
||||
)
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
clearTimeout(timeoutId)
|
||||
isCancelled = true
|
||||
}
|
||||
},
|
||||
[
|
||||
|
||||
@@ -11,40 +11,23 @@ export const useTransactionFinder = ({ txHash, web3 }: { txHash: string; web3: M
|
||||
() => {
|
||||
if (!txHash || !web3) return
|
||||
|
||||
const subscriptions: number[] = []
|
||||
let timeoutId: number
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
|
||||
const getReceipt = async (
|
||||
web3: Web3,
|
||||
txHash: string,
|
||||
setReceipt: Function,
|
||||
setStatus: Function,
|
||||
subscriptions: number[]
|
||||
) => {
|
||||
const getReceipt = async () => {
|
||||
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
||||
setReceipt(txReceipt)
|
||||
|
||||
if (!txReceipt) {
|
||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||
const timeoutId = setTimeout(
|
||||
() => getReceipt(web3, txHash, setReceipt, setStatus, subscriptions),
|
||||
HOME_RPC_POLLING_INTERVAL
|
||||
)
|
||||
subscriptions.push(timeoutId)
|
||||
timeoutId = setTimeout(getReceipt, HOME_RPC_POLLING_INTERVAL)
|
||||
} else {
|
||||
setStatus(TRANSACTION_STATUS.FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
getReceipt(web3, txHash, setReceipt, setStatus, subscriptions)
|
||||
return () => {
|
||||
unsubscribe()
|
||||
}
|
||||
getReceipt()
|
||||
|
||||
return () => clearTimeout(timeoutId)
|
||||
},
|
||||
[txHash, web3]
|
||||
)
|
||||
|
||||
@@ -31,19 +31,14 @@ export const useTransactionStatus = ({
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
const subscriptions: Array<number> = []
|
||||
if (!chainId || !txHash || !home.chainId || !foreign.chainId || !home.web3 || !foreign.web3) return
|
||||
const isHome = chainId === home.chainId
|
||||
const web3 = isHome ? home.web3 : foreign.web3
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
let timeoutId: number
|
||||
|
||||
const getReceipt = async () => {
|
||||
if (!chainId || !txHash || !home.chainId || !foreign.chainId || !home.web3 || !foreign.web3) return
|
||||
setLoading(true)
|
||||
const isHome = chainId === home.chainId
|
||||
const web3 = isHome ? home.web3 : foreign.web3
|
||||
|
||||
let txReceipt
|
||||
|
||||
@@ -59,8 +54,7 @@ export const useTransactionStatus = ({
|
||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
||||
setMessages([{ id: txHash, data: '' }])
|
||||
const timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
||||
subscriptions.push(timeoutId)
|
||||
timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
||||
} else {
|
||||
const blockNumber = txReceipt.blockNumber
|
||||
const block = await getBlock(web3, blockNumber)
|
||||
@@ -70,9 +64,9 @@ export const useTransactionStatus = ({
|
||||
if (txReceipt.status) {
|
||||
let bridgeMessages: Array<MessageObject>
|
||||
if (isHome) {
|
||||
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
|
||||
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, web3, home.bridgeAddress)
|
||||
} else {
|
||||
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
|
||||
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, web3, foreign.bridgeAddress)
|
||||
}
|
||||
|
||||
if (bridgeMessages.length === 0) {
|
||||
@@ -98,14 +92,9 @@ export const useTransactionStatus = ({
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// unsubscribe from previous txHash
|
||||
unsubscribe()
|
||||
|
||||
getReceipt()
|
||||
return () => {
|
||||
// unsubscribe when unmount component
|
||||
unsubscribe()
|
||||
}
|
||||
|
||||
return () => clearTimeout(timeoutId)
|
||||
},
|
||||
[
|
||||
txHash,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { TransactionReceipt } from 'web3-eth'
|
||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
||||
|
||||
export interface useValidatorContractParams {
|
||||
fromHome: boolean
|
||||
@@ -30,10 +31,12 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
||||
contract: Maybe<Contract>,
|
||||
receipt: TransactionReceipt,
|
||||
setResult: Function,
|
||||
snapshotProvider: SnapshotProvider
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3,
|
||||
api: string
|
||||
) => {
|
||||
if (!contract) return
|
||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider)
|
||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
@@ -41,32 +44,35 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
||||
contract: Maybe<Contract>,
|
||||
receipt: TransactionReceipt,
|
||||
setResult: Function,
|
||||
snapshotProvider: SnapshotProvider
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3,
|
||||
api: string
|
||||
) => {
|
||||
if (!contract) return
|
||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider)
|
||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
const web3 = fromHome ? home.web3 : foreign.web3
|
||||
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
const web3 = fromHome ? home.web3 : foreign.web3
|
||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||
|
||||
if (!web3 || !bridgeContract) return
|
||||
callValidatorContract(bridgeContract, web3, setValidatorContract)
|
||||
},
|
||||
[home.web3, foreign.web3, home.bridgeContract, foreign.bridgeContract, fromHome]
|
||||
[web3, bridgeContract]
|
||||
)
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!receipt) return
|
||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider)
|
||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider)
|
||||
if (!web3 || !receipt) return
|
||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider, web3, api)
|
||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider, web3, api)
|
||||
},
|
||||
[validatorContract, receipt, fromHome]
|
||||
[validatorContract, receipt, web3, snapshotProvider, api]
|
||||
)
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('getRequiredBlockConfirmations', () => {
|
||||
|
||||
test('Should call requiredBlockConfirmations method if no events present', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
getPastEvents: async () => {
|
||||
return []
|
||||
},
|
||||
methods: methodsBuilder('1')
|
||||
@@ -37,7 +37,7 @@ describe('getRequiredBlockConfirmations', () => {
|
||||
})
|
||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||
methods: methodsBuilder('3')
|
||||
} as unknown) as Contract
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('getRequiredBlockConfirmations', () => {
|
||||
})
|
||||
test('Should call to get events if block number was not included in the snapshot', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
@@ -102,7 +102,7 @@ describe('getRequiredBlockConfirmations', () => {
|
||||
})
|
||||
test('Should use the most updated event', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
@@ -141,7 +141,7 @@ describe('getRequiredBlockConfirmations', () => {
|
||||
describe('getRequiredSignatures', () => {
|
||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [])
|
||||
getPastEvents: jest.fn().mockImplementation(async () => [])
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
@@ -173,7 +173,7 @@ describe('getRequiredSignatures', () => {
|
||||
})
|
||||
test('Should call to get events if block number is higher than the snapshot block number', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||
{
|
||||
blockNumber: 15,
|
||||
returnValues: {
|
||||
@@ -216,7 +216,7 @@ describe('getRequiredSignatures', () => {
|
||||
})
|
||||
test('Should use the most updated event before the block number', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||
{
|
||||
blockNumber: 15,
|
||||
returnValues: {
|
||||
@@ -270,7 +270,7 @@ describe('getValidatorList', () => {
|
||||
test('Should return the current validator list if no events found', async () => {
|
||||
const currentValidators = [validator1, validator2, validator3]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
@@ -301,7 +301,7 @@ describe('getValidatorList', () => {
|
||||
test('If validator was added later from snapshot it should not include it', async () => {
|
||||
const currentValidators = [validator1, validator2, validator3]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
@@ -340,7 +340,7 @@ describe('getValidatorList', () => {
|
||||
test('If validator was added later from chain it should not include it', async () => {
|
||||
const currentValidators = [validator1, validator2, validator3]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(event => {
|
||||
getPastEvents: jest.fn().mockImplementation(async event => {
|
||||
if (event === 'ValidatorAdded') {
|
||||
return [
|
||||
{
|
||||
@@ -385,7 +385,7 @@ describe('getValidatorList', () => {
|
||||
test('If validator was removed later from snapshot it should include it', async () => {
|
||||
const currentValidators = [validator1, validator2]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
@@ -424,7 +424,7 @@ describe('getValidatorList', () => {
|
||||
test('If validator was removed later from chain it should include it', async () => {
|
||||
const currentValidators = [validator1, validator2]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(event => {
|
||||
getPastEvents: jest.fn().mockImplementation(async event => {
|
||||
if (event === 'ValidatorRemoved') {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@ const bridgeContract = {
|
||||
}
|
||||
} as Contract
|
||||
const requiredSignatures = 2
|
||||
const waitingBlocksResolved = true
|
||||
const isCancelled = () => false
|
||||
let subscriptions: Array<number> = []
|
||||
const timestamp = 1594045859
|
||||
const getFailedTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
||||
@@ -94,8 +94,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -177,8 +177,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -241,8 +241,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -340,8 +340,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -453,8 +453,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -557,8 +557,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -678,8 +678,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
@@ -746,8 +746,8 @@ describe('getConfirmationsForTx', () => {
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
|
||||
@@ -4,7 +4,6 @@ import Web3 from 'web3'
|
||||
import { getFinalizationEvent } from '../getFinalizationEvent'
|
||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
||||
|
||||
const eventName = 'RelayedMessage'
|
||||
const timestamp = 1594045859
|
||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||
const txHash = '0xdab36c9210e7e45fb82af10ffe4960461e41661dce0c9cd36b2843adaa1df156'
|
||||
@@ -20,12 +19,11 @@ const web3 = ({
|
||||
toChecksumAddress: (a: string) => a
|
||||
}
|
||||
} as unknown) as Web3
|
||||
const waitingBlocksResolved = true
|
||||
const message = {
|
||||
id: '0x123',
|
||||
data: '0x123456789'
|
||||
}
|
||||
const interval = 10000
|
||||
const isCancelled = () => false
|
||||
let subscriptions: Array<number> = []
|
||||
|
||||
const event = {
|
||||
@@ -50,7 +48,7 @@ beforeEach(() => {
|
||||
describe('getFinalizationEvent', () => {
|
||||
test('should get finalization event and not try to get failed or pending transactions', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
getPastEvents: async () => {
|
||||
return [event]
|
||||
}
|
||||
} as unknown) as Contract
|
||||
@@ -66,13 +64,11 @@ describe('getFinalizationEvent', () => {
|
||||
await getFinalizationEvent(
|
||||
true,
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
@@ -102,7 +98,7 @@ describe('getFinalizationEvent', () => {
|
||||
})
|
||||
test('should retry to get finalization event and not try to get failed or pending transactions if foreign to home transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
getPastEvents: async () => {
|
||||
return []
|
||||
}
|
||||
} as unknown) as Contract
|
||||
@@ -118,13 +114,11 @@ describe('getFinalizationEvent', () => {
|
||||
await getFinalizationEvent(
|
||||
true,
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
@@ -147,7 +141,7 @@ describe('getFinalizationEvent', () => {
|
||||
})
|
||||
test('should retry to get finalization event and try to get failed and pending transactions if home to foreign transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
getPastEvents: async () => {
|
||||
return []
|
||||
},
|
||||
options: {
|
||||
@@ -170,13 +164,11 @@ describe('getFinalizationEvent', () => {
|
||||
await getFinalizationEvent(
|
||||
true,
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
@@ -199,7 +191,7 @@ describe('getFinalizationEvent', () => {
|
||||
})
|
||||
test('should retry to get finalization event and not to try to get failed transaction if pending transactions found if home to foreign transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
getPastEvents: async () => {
|
||||
return []
|
||||
},
|
||||
options: {
|
||||
@@ -222,13 +214,11 @@ describe('getFinalizationEvent', () => {
|
||||
await getFinalizationEvent(
|
||||
true,
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
@@ -258,7 +248,7 @@ describe('getFinalizationEvent', () => {
|
||||
})
|
||||
test('should retry to get finalization event even if failed transaction found if home to foreign transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
getPastEvents: async () => {
|
||||
return []
|
||||
},
|
||||
options: {
|
||||
@@ -281,13 +271,11 @@ describe('getFinalizationEvent', () => {
|
||||
await getFinalizationEvent(
|
||||
true,
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
subscriptions.push.bind(subscriptions),
|
||||
isCancelled,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import { EventData } from 'web3-eth-contract'
|
||||
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||
import { getLogs } from './explorer'
|
||||
import Web3 from 'web3'
|
||||
|
||||
const getPastEventsWithFallback = (
|
||||
api: string,
|
||||
web3: Web3 | null,
|
||||
contract: Contract,
|
||||
eventName: string,
|
||||
options: any
|
||||
) =>
|
||||
contract
|
||||
.getPastEvents(eventName, options)
|
||||
.catch(() => (api && web3 ? getLogs(api, web3, contract, eventName, options) : []))
|
||||
|
||||
export const getRequiredBlockConfirmations = async (
|
||||
contract: Contract,
|
||||
blockNumber: number,
|
||||
snapshotProvider: SnapshotProvider
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3 | null = null,
|
||||
api: string = ''
|
||||
) => {
|
||||
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
|
||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||
|
||||
let contractEvents: EventData[] = []
|
||||
if (blockNumber > snapshotBlockNumber) {
|
||||
contractEvents = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||
contractEvents = await getPastEventsWithFallback(api, web3, contract, 'RequiredBlockConfirmationChanged', {
|
||||
fromBlock: snapshotBlockNumber + 1,
|
||||
toBlock: blockNumber
|
||||
})
|
||||
@@ -38,14 +53,16 @@ export const getValidatorAddress = (contract: Contract) => contract.methods.vali
|
||||
export const getRequiredSignatures = async (
|
||||
contract: Contract,
|
||||
blockNumber: number,
|
||||
snapshotProvider: SnapshotProvider
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3 | null = null,
|
||||
api: string = ''
|
||||
) => {
|
||||
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||
|
||||
let contractEvents: EventData[] = []
|
||||
if (blockNumber > snapshotBlockNumber) {
|
||||
contractEvents = await contract.getPastEvents('RequiredSignaturesChanged', {
|
||||
contractEvents = await getPastEventsWithFallback(api, web3, contract, 'RequiredSignaturesChanged', {
|
||||
fromBlock: snapshotBlockNumber + 1,
|
||||
toBlock: blockNumber
|
||||
})
|
||||
@@ -59,7 +76,13 @@ export const getRequiredSignatures = async (
|
||||
return parseInt(requiredSignatures)
|
||||
}
|
||||
|
||||
export const getValidatorList = async (contract: Contract, blockNumber: number, snapshotProvider: SnapshotProvider) => {
|
||||
export const getValidatorList = async (
|
||||
contract: Contract,
|
||||
blockNumber: number,
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3 | null = null,
|
||||
api: string = ''
|
||||
) => {
|
||||
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||
@@ -67,10 +90,10 @@ export const getValidatorList = async (contract: Contract, blockNumber: number,
|
||||
const fromBlock = snapshotBlockNumber > blockNumber ? snapshotBlockNumber + 1 : blockNumber
|
||||
const [currentList, added, removed] = await Promise.all([
|
||||
contract.methods.validatorList().call(),
|
||||
contract.getPastEvents('ValidatorAdded', {
|
||||
getPastEventsWithFallback(api, web3, contract, 'ValidatorAdded', {
|
||||
fromBlock
|
||||
}),
|
||||
contract.getPastEvents('ValidatorRemoved', {
|
||||
getPastEventsWithFallback(api, web3, contract, 'ValidatorRemoved', {
|
||||
fromBlock
|
||||
})
|
||||
])
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { BlockNumberProvider } from '../services/BlockNumberProvider'
|
||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import { EventData } from 'web3-eth-contract'
|
||||
|
||||
export const checkWaitingBlocksForExecution = async (
|
||||
blockProvider: BlockNumberProvider,
|
||||
interval: number,
|
||||
targetBlock: number,
|
||||
collectedSignaturesEvent: EventData,
|
||||
setWaitingBlocksForExecution: Function,
|
||||
setWaitingBlocksForExecutionResolved: Function,
|
||||
setExecutionData: Function,
|
||||
subscriptions: number[]
|
||||
) => {
|
||||
const currentBlock = blockProvider.get()
|
||||
|
||||
if (currentBlock && currentBlock >= targetBlock) {
|
||||
const undefinedExecutionState = {
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||
txHash: '',
|
||||
timestamp: 0,
|
||||
executionResult: false
|
||||
}
|
||||
setExecutionData(
|
||||
(data: any) =>
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
? undefinedExecutionState
|
||||
: data
|
||||
)
|
||||
setWaitingBlocksForExecutionResolved(true)
|
||||
setWaitingBlocksForExecution(false)
|
||||
} else {
|
||||
let nextInterval = interval
|
||||
if (!currentBlock) {
|
||||
nextInterval = 500
|
||||
} else {
|
||||
setWaitingBlocksForExecution(true)
|
||||
const waitingExecutionState = {
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||
txHash: '',
|
||||
timestamp: 0,
|
||||
executionResult: false
|
||||
}
|
||||
setExecutionData(
|
||||
(data: any) =>
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
||||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
? waitingExecutionState
|
||||
: data
|
||||
)
|
||||
}
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
checkWaitingBlocksForExecution(
|
||||
blockProvider,
|
||||
interval,
|
||||
targetBlock,
|
||||
collectedSignaturesEvent,
|
||||
setWaitingBlocksForExecution,
|
||||
setWaitingBlocksForExecutionResolved,
|
||||
setExecutionData,
|
||||
subscriptions
|
||||
),
|
||||
nextInterval
|
||||
)
|
||||
subscriptions.push(timeoutId)
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import {
|
||||
MAX_TX_SEARCH_BLOCK_RANGE,
|
||||
SUBMIT_SIGNATURE_HASH
|
||||
} from '../config/constants'
|
||||
import { AbiItem } from 'web3-utils'
|
||||
import Web3 from 'web3'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
|
||||
export interface APITransaction {
|
||||
timeStamp: string
|
||||
@@ -47,10 +50,15 @@ export interface GetTransactionParams extends GetPendingTransactionParams {
|
||||
}
|
||||
|
||||
export const fetchAccountTransactions = async ({ account, startBlock, endBlock, api }: AccountTransactionsParams) => {
|
||||
const params = `module=account&action=txlist&address=${account}&filterby=from&startblock=${startBlock}&endblock=${endBlock}`
|
||||
const url = api.includes('blockscout') ? `${api}?${params}` : `${api}&${params}`
|
||||
const url = new URL(api)
|
||||
url.searchParams.append('module', 'account')
|
||||
url.searchParams.append('action', 'txlist')
|
||||
url.searchParams.append('address', account)
|
||||
url.searchParams.append('filterby', 'from')
|
||||
url.searchParams.append('startblock', startBlock.toString())
|
||||
url.searchParams.append('endblock', endBlock.toString())
|
||||
|
||||
const result = await fetch(url).then(res => res.json())
|
||||
const result = await fetch(url.toString()).then(res => res.json())
|
||||
|
||||
if (result.message === 'No transactions found') {
|
||||
return []
|
||||
@@ -66,10 +74,13 @@ export const fetchPendingTransactions = async ({
|
||||
if (!api.includes('blockscout')) {
|
||||
return []
|
||||
}
|
||||
const url = `${api}?module=account&action=pendingtxlist&address=${account}`
|
||||
const url = new URL(api)
|
||||
url.searchParams.append('module', 'account')
|
||||
url.searchParams.append('action', 'pendingtxlist')
|
||||
url.searchParams.append('address', account)
|
||||
|
||||
try {
|
||||
const result = await fetch(url).then(res => res.json())
|
||||
const result = await fetch(url.toString()).then(res => res.json())
|
||||
if (result.status === '0') {
|
||||
return []
|
||||
}
|
||||
@@ -85,9 +96,13 @@ export const getClosestBlockByTimestamp = async (api: string, timestamp: number)
|
||||
throw new Error('Blockscout does not support getblocknobytime')
|
||||
}
|
||||
|
||||
const url = `${api}&module=block&action=getblocknobytime×tamp=${timestamp}&closest=before`
|
||||
const url = new URL(api)
|
||||
url.searchParams.append('module', 'block')
|
||||
url.searchParams.append('action', 'getblocknobytime')
|
||||
url.searchParams.append('timestamp', timestamp.toString())
|
||||
url.searchParams.append('closest', 'before')
|
||||
|
||||
const blockNumber = await fetch(url).then(res => res.json())
|
||||
const blockNumber = await fetch(url.toString()).then(res => res.json())
|
||||
|
||||
return parseInt(blockNumber.result)
|
||||
}
|
||||
@@ -144,6 +159,41 @@ export const getAccountTransactions = async ({
|
||||
return transactionsCache[key].transactions
|
||||
}
|
||||
|
||||
export const getLogs = async (
|
||||
api: string,
|
||||
web3: Web3,
|
||||
contract: Contract,
|
||||
event: string,
|
||||
options: { fromBlock: number; toBlock: number | 'latest'; topics: (string | null)[] }
|
||||
) => {
|
||||
const abi = contract.options.jsonInterface.find((abi: AbiItem) => abi.type === 'event' && abi.name === event)!
|
||||
|
||||
const url = new URL(api)
|
||||
url.searchParams.append('module', 'logs')
|
||||
url.searchParams.append('action', 'getLogs')
|
||||
url.searchParams.append('address', contract.options.address)
|
||||
url.searchParams.append('fromBlock', options.fromBlock.toString())
|
||||
url.searchParams.append('toBlock', (options.toBlock || 'latest').toString())
|
||||
|
||||
const topics = [web3.eth.abi.encodeEventSignature(abi), ...(options.topics || [])]
|
||||
for (let i = 0; i < topics.length; i++) {
|
||||
if (topics[i] !== null) {
|
||||
url.searchParams.append(`topic${i}`, topics[i] as string)
|
||||
for (let j = 0; j < i; j++) {
|
||||
url.searchParams.append(`topic${j}_${i}_opr`, 'and')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const logs = await fetch(url.toString()).then(res => res.json())
|
||||
|
||||
return logs.result.map((log: any) => ({
|
||||
transactionHash: log.transactionHash,
|
||||
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
||||
returnValues: web3.eth.abi.decodeLog(abi.inputs!, log.data, log.topics.slice(1))
|
||||
}))
|
||||
}
|
||||
|
||||
const filterReceiver = (to: string) => (tx: APITransaction) => tx.to.toLowerCase() === to.toLowerCase()
|
||||
|
||||
export const getFailedTransactions = async (
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import Web3 from 'web3'
|
||||
import { Contract, EventData } from 'web3-eth-contract'
|
||||
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||
import { BLOCK_RANGE } from '../config/constants'
|
||||
|
||||
export const getCollectedSignaturesEvent = async (
|
||||
web3: Maybe<Web3>,
|
||||
contract: Maybe<Contract>,
|
||||
fromBlock: number,
|
||||
toBlock: number,
|
||||
messageHash: string,
|
||||
setCollectedSignaturesEvent: Function,
|
||||
subscriptions: number[]
|
||||
) => {
|
||||
if (!web3 || !contract) return
|
||||
const currentBlock = homeBlockNumberProvider.get()
|
||||
|
||||
let events: EventData[] = []
|
||||
let securedToBlock = toBlock
|
||||
if (currentBlock) {
|
||||
// prevent errors if the toBlock parameter is bigger than the latest
|
||||
securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
|
||||
events = await contract.getPastEvents('CollectedSignatures', {
|
||||
fromBlock,
|
||||
toBlock: securedToBlock
|
||||
})
|
||||
}
|
||||
|
||||
const filteredEvents = events.filter(e => e.returnValues.messageHash === messageHash)
|
||||
|
||||
if (filteredEvents.length) {
|
||||
const event = filteredEvents[0]
|
||||
setCollectedSignaturesEvent(event)
|
||||
} else {
|
||||
const newFromBlock = currentBlock ? securedToBlock : fromBlock
|
||||
const newToBlock = currentBlock ? toBlock + BLOCK_RANGE : toBlock
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
getCollectedSignaturesEvent(
|
||||
web3,
|
||||
contract,
|
||||
newFromBlock,
|
||||
newToBlock,
|
||||
messageHash,
|
||||
setCollectedSignaturesEvent,
|
||||
subscriptions
|
||||
),
|
||||
500
|
||||
)
|
||||
subscriptions.push(timeoutId)
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,15 @@ const mergeConfirmations = (oldConfirmations: BasicConfirmationParam[], newConfi
|
||||
|
||||
export const getConfirmationsForTx = async (
|
||||
messageData: string,
|
||||
web3: Maybe<Web3>,
|
||||
web3: Web3,
|
||||
validatorList: string[],
|
||||
bridgeContract: Maybe<Contract>,
|
||||
bridgeContract: Contract,
|
||||
fromHome: boolean,
|
||||
setResult: Function,
|
||||
requiredSignatures: number,
|
||||
setSignatureCollected: Function,
|
||||
waitingBlocksResolved: boolean,
|
||||
subscriptions: number[],
|
||||
setTimeoutId: (timeoutId: number) => void,
|
||||
isCancelled: () => boolean,
|
||||
startBlock: number,
|
||||
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
||||
setFailedConfirmations: Function,
|
||||
@@ -45,8 +45,6 @@ export const getConfirmationsForTx = async (
|
||||
setPendingConfirmations: Function,
|
||||
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
||||
) => {
|
||||
if (!web3 || !validatorList || !validatorList.length || !bridgeContract || !waitingBlocksResolved) return
|
||||
|
||||
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
||||
|
||||
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
||||
@@ -88,6 +86,14 @@ export const getConfirmationsForTx = async (
|
||||
setPendingConfirmations(validatorPendingConfirmations.length > 0)
|
||||
} else {
|
||||
setPendingConfirmations(false)
|
||||
if (fromHome) {
|
||||
// fetch collected signatures for possible manual processing
|
||||
setSignatureCollected(
|
||||
await Promise.all(
|
||||
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const undefinedConfirmations = validatorConfirmations.filter(
|
||||
@@ -117,15 +123,6 @@ export const getConfirmationsForTx = async (
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
||||
}))
|
||||
updateConfirmations(notRequiredConfirmations)
|
||||
|
||||
if (fromHome) {
|
||||
// fetch collected signatures for possible manual processing
|
||||
setSignatureCollected(
|
||||
await Promise.all(
|
||||
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// get transactions from success signatures
|
||||
@@ -144,28 +141,30 @@ export const getConfirmationsForTx = async (
|
||||
(!hasEnoughSignatures && missingConfirmations.length > 0) ||
|
||||
successConfirmationWithTxFound.length < successConfirmationWithData.length
|
||||
) {
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
fromHome,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
startBlock,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
),
|
||||
HOME_RPC_POLLING_INTERVAL
|
||||
)
|
||||
subscriptions.push(timeoutId)
|
||||
if (!isCancelled()) {
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
fromHome,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
setTimeoutId,
|
||||
isCancelled,
|
||||
startBlock,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
),
|
||||
HOME_RPC_POLLING_INTERVAL
|
||||
)
|
||||
setTimeoutId(timeoutId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,47 @@
|
||||
import { Contract, EventData } from 'web3-eth-contract'
|
||||
import Web3 from 'web3'
|
||||
import { CACHE_KEY_EXECUTION_FAILED, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import {
|
||||
CACHE_KEY_EXECUTION_FAILED,
|
||||
FOREIGN_EXPLORER_API,
|
||||
FOREIGN_RPC_POLLING_INTERVAL,
|
||||
HOME_EXPLORER_API,
|
||||
HOME_RPC_POLLING_INTERVAL,
|
||||
VALIDATOR_CONFIRMATION_STATUS
|
||||
} from '../config/constants'
|
||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
||||
import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer'
|
||||
import {
|
||||
APIPendingTransaction,
|
||||
APITransaction,
|
||||
GetTransactionParams,
|
||||
GetPendingTransactionParams,
|
||||
getLogs
|
||||
} from './explorer'
|
||||
import { getBlock, MessageObject } from './web3'
|
||||
import validatorsCache from '../services/ValidatorsCache'
|
||||
import { foreignBlockNumberProvider, homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||
|
||||
export const getSuccessExecutionData = async (contract: Contract, eventName: string, web3: Web3, messageId: string) => {
|
||||
const getPastEventsWithFallback = (api: string, web3: Web3, contract: Contract, eventName: string, options: any) =>
|
||||
contract.getPastEvents(eventName, options).catch(
|
||||
() =>
|
||||
api
|
||||
? getLogs(api, web3, contract, eventName, {
|
||||
fromBlock: options.fromBlock,
|
||||
toBlock: options.toBlock,
|
||||
topics: [null, null, options.filter.messageId]
|
||||
})
|
||||
: []
|
||||
)
|
||||
|
||||
export const getSuccessExecutionData = async (
|
||||
contract: Contract,
|
||||
eventName: string,
|
||||
web3: Web3,
|
||||
messageId: string,
|
||||
api: string = ''
|
||||
) => {
|
||||
// Since it filters by the message id, only one event will be fetched
|
||||
// so there is no need to limit the range of the block to reduce the network traffic
|
||||
const events: EventData[] = await contract.getPastEvents(eventName, {
|
||||
const events: EventData[] = await getPastEventsWithFallback(api, web3, contract, eventName, {
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest',
|
||||
filter: {
|
||||
@@ -40,14 +71,12 @@ export const getSuccessExecutionData = async (contract: Contract, eventName: str
|
||||
|
||||
export const getFinalizationEvent = async (
|
||||
fromHome: boolean,
|
||||
contract: Maybe<Contract>,
|
||||
eventName: string,
|
||||
web3: Maybe<Web3>,
|
||||
contract: Contract,
|
||||
web3: Web3,
|
||||
setResult: React.Dispatch<React.SetStateAction<ExecutionData>>,
|
||||
waitingBlocksResolved: boolean,
|
||||
message: MessageObject,
|
||||
interval: number,
|
||||
subscriptions: number[],
|
||||
setTimeoutId: (timeoutId: number) => void,
|
||||
isCancelled: () => boolean,
|
||||
startBlock: number,
|
||||
collectedSignaturesEvent: Maybe<EventData>,
|
||||
getFailedExecution: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
||||
@@ -56,8 +85,11 @@ export const getFinalizationEvent = async (
|
||||
setPendingExecution: Function,
|
||||
setExecutionEventsFetched: Function
|
||||
) => {
|
||||
if (!contract || !web3 || !waitingBlocksResolved) return
|
||||
const successExecutionData = await getSuccessExecutionData(contract, eventName, web3, message.id)
|
||||
const eventName = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
|
||||
const api = fromHome ? FOREIGN_EXPLORER_API : HOME_EXPLORER_API
|
||||
|
||||
const successExecutionData = await getSuccessExecutionData(contract, eventName, web3, message.id, api)
|
||||
|
||||
if (successExecutionData) {
|
||||
setResult(successExecutionData)
|
||||
} else {
|
||||
@@ -120,28 +152,28 @@ export const getFinalizationEvent = async (
|
||||
}
|
||||
}
|
||||
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
getFinalizationEvent(
|
||||
fromHome,
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
startBlock,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
),
|
||||
interval
|
||||
)
|
||||
subscriptions.push(timeoutId)
|
||||
if (!isCancelled()) {
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
getFinalizationEvent(
|
||||
fromHome,
|
||||
contract,
|
||||
web3,
|
||||
setResult,
|
||||
message,
|
||||
setTimeoutId,
|
||||
isCancelled,
|
||||
startBlock,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution,
|
||||
setExecutionEventsFetched
|
||||
),
|
||||
fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
|
||||
)
|
||||
setTimeoutId(timeoutId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import { BlockNumberProvider } from '../services/BlockNumberProvider'
|
||||
|
||||
export const checkSignaturesWaitingForBLocks = async (
|
||||
targetBlock: number,
|
||||
setWaitingStatus: Function,
|
||||
setWaitingBlocksResolved: Function,
|
||||
validatorList: string[],
|
||||
setConfirmations: Function,
|
||||
blockProvider: BlockNumberProvider,
|
||||
interval: number,
|
||||
subscriptions: number[]
|
||||
) => {
|
||||
const currentBlock = blockProvider.get()
|
||||
|
||||
if (currentBlock && currentBlock >= targetBlock) {
|
||||
setWaitingBlocksResolved(true)
|
||||
setWaitingStatus(false)
|
||||
} else {
|
||||
let nextInterval = interval
|
||||
if (!currentBlock) {
|
||||
nextInterval = 500
|
||||
} else {
|
||||
const validatorsWaiting = validatorList.map(validator => {
|
||||
return {
|
||||
validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||
}
|
||||
})
|
||||
setWaitingStatus(true)
|
||||
setConfirmations(validatorsWaiting)
|
||||
}
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
checkSignaturesWaitingForBLocks(
|
||||
targetBlock,
|
||||
setWaitingStatus,
|
||||
setWaitingBlocksResolved,
|
||||
validatorList,
|
||||
setConfirmations,
|
||||
blockProvider,
|
||||
interval,
|
||||
subscriptions
|
||||
),
|
||||
nextInterval
|
||||
)
|
||||
subscriptions.push(timeoutId)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,13 +1,7 @@
|
||||
const HOME_NATIVE_TO_ERC_ABI = require('../contracts/build/contracts/HomeBridgeNativeToErc').abi
|
||||
const FOREIGN_NATIVE_TO_ERC_ABI = require('../contracts/build/contracts/ForeignBridgeNativeToErc').abi
|
||||
const HOME_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeBridgeErcToErc').abi
|
||||
const FOREIGN_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignBridgeErc677ToErc677').abi
|
||||
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
|
||||
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignBridgeErcToNative').abi
|
||||
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/XDaiForeignBridge.json').abi
|
||||
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
|
||||
const ERC677_ABI = require('../contracts/build/contracts/ERC677').abi
|
||||
const ERC677_BRIDGE_TOKEN_ABI = require('../contracts/build/contracts/ERC677BridgeToken').abi
|
||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockReward').abi
|
||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockRewardMock').abi
|
||||
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
|
||||
const REWARDABLE_VALIDATORS_ABI = require('../contracts/build/contracts/RewardableValidators').abi
|
||||
const HOME_AMB_ABI = require('../contracts/build/contracts/HomeAMB').abi
|
||||
@@ -15,43 +9,9 @@ const FOREIGN_AMB_ABI = require('../contracts/build/contracts/ForeignAMB').abi
|
||||
const BOX_ABI = require('../contracts/build/contracts/Box').abi
|
||||
const HOME_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeAMBErc677ToErc677').abi
|
||||
const FOREIGN_AMB_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignAMBErc677ToErc677').abi
|
||||
const HOME_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/HomeStakeTokenMediator').abi
|
||||
const FOREIGN_STAKE_ERC_TO_ERC_ABI = require('../contracts/build/contracts/ForeignStakeTokenMediator').abi
|
||||
|
||||
const { HOME_V1_ABI, FOREIGN_V1_ABI } = require('./v1Abis')
|
||||
const { BRIDGE_MODES } = require('./constants')
|
||||
|
||||
const ERC20_BYTES32_ABI = [
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'name',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'symbol',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
|
||||
const OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI = [
|
||||
{
|
||||
anonymous: false,
|
||||
@@ -85,27 +45,15 @@ const OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI = [
|
||||
function getBridgeABIs(bridgeMode) {
|
||||
let HOME_ABI = null
|
||||
let FOREIGN_ABI = null
|
||||
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
|
||||
HOME_ABI = HOME_NATIVE_TO_ERC_ABI
|
||||
FOREIGN_ABI = FOREIGN_NATIVE_TO_ERC_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||
HOME_ABI = HOME_ERC_TO_ERC_ABI
|
||||
FOREIGN_ABI = FOREIGN_ERC_TO_ERC_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
HOME_ABI = HOME_ERC_TO_NATIVE_ABI
|
||||
FOREIGN_ABI = FOREIGN_ERC_TO_NATIVE_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
|
||||
HOME_ABI = HOME_V1_ABI
|
||||
FOREIGN_ABI = FOREIGN_V1_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||
HOME_ABI = HOME_AMB_ABI
|
||||
FOREIGN_ABI = FOREIGN_AMB_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC) {
|
||||
HOME_ABI = HOME_AMB_ERC_TO_ERC_ABI
|
||||
FOREIGN_ABI = FOREIGN_AMB_ERC_TO_ERC_ABI
|
||||
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
|
||||
HOME_ABI = HOME_STAKE_ERC_TO_ERC_ABI
|
||||
FOREIGN_ABI = FOREIGN_STAKE_ERC_TO_ERC_ABI
|
||||
} else {
|
||||
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
|
||||
}
|
||||
@@ -115,26 +63,15 @@ function getBridgeABIs(bridgeMode) {
|
||||
|
||||
module.exports = {
|
||||
getBridgeABIs,
|
||||
HOME_NATIVE_TO_ERC_ABI,
|
||||
FOREIGN_NATIVE_TO_ERC_ABI,
|
||||
HOME_ERC_TO_ERC_ABI,
|
||||
FOREIGN_ERC_TO_ERC_ABI,
|
||||
HOME_ERC_TO_NATIVE_ABI,
|
||||
FOREIGN_ERC_TO_NATIVE_ABI,
|
||||
ERC20_ABI,
|
||||
ERC677_ABI,
|
||||
ERC677_BRIDGE_TOKEN_ABI,
|
||||
BLOCK_REWARD_ABI,
|
||||
BRIDGE_VALIDATORS_ABI,
|
||||
REWARDABLE_VALIDATORS_ABI,
|
||||
HOME_V1_ABI,
|
||||
FOREIGN_V1_ABI,
|
||||
ERC20_BYTES32_ABI,
|
||||
HOME_AMB_ABI,
|
||||
FOREIGN_AMB_ABI,
|
||||
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI,
|
||||
OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI,
|
||||
BOX_ABI,
|
||||
HOME_STAKE_ERC_TO_ERC_ABI,
|
||||
FOREIGN_STAKE_ERC_TO_ERC_ABI
|
||||
BOX_ABI
|
||||
}
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
const BRIDGE_MODES = {
|
||||
NATIVE_TO_ERC: 'NATIVE_TO_ERC',
|
||||
ERC_TO_ERC: 'ERC_TO_ERC',
|
||||
ERC_TO_NATIVE: 'ERC_TO_NATIVE',
|
||||
NATIVE_TO_ERC_V1: 'NATIVE_TO_ERC_V1',
|
||||
ARBITRARY_MESSAGE: 'ARBITRARY_MESSAGE',
|
||||
AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC',
|
||||
STAKE_AMB_ERC_TO_ERC: 'STAKE_AMB_ERC_TO_ERC'
|
||||
}
|
||||
|
||||
const ERC_TYPES = {
|
||||
ERC20: 'ERC20',
|
||||
ERC677: 'ERC677'
|
||||
}
|
||||
|
||||
const FEE_MANAGER_MODE = {
|
||||
ONE_DIRECTION: 'ONE_DIRECTION',
|
||||
BOTH_DIRECTIONS: 'BOTH_DIRECTIONS',
|
||||
ONE_DIRECTION_STAKE: 'ONE_DIRECTION_STAKE',
|
||||
UNDEFINED: 'UNDEFINED'
|
||||
AMB_ERC_TO_ERC: 'AMB_ERC_TO_ERC'
|
||||
}
|
||||
|
||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
|
||||
module.exports = {
|
||||
BRIDGE_MODES,
|
||||
ERC_TYPES,
|
||||
FEE_MANAGER_MODE,
|
||||
ZERO_ADDRESS
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const { soliditySha3 } = require('web3-utils')
|
||||
|
||||
function strip0x(input) {
|
||||
return input.replace(/^0x/, '')
|
||||
}
|
||||
@@ -39,8 +41,35 @@ const normalizeAMBMessageEvent = e => {
|
||||
return parseAMBMessage(msgData)
|
||||
}
|
||||
|
||||
const ambInformationSignatures = [
|
||||
'eth_call(address,bytes)',
|
||||
'eth_call(address,bytes,uint256)',
|
||||
'eth_call(address,address,uint256,bytes)',
|
||||
'eth_blockNumber()',
|
||||
'eth_getBlockByNumber()',
|
||||
'eth_getBlockByNumber(uint256)',
|
||||
'eth_getBlockByHash(bytes32)',
|
||||
'eth_getBalance(address)',
|
||||
'eth_getBalance(address,uint256)',
|
||||
'eth_getTransactionCount(address)',
|
||||
'eth_getTransactionCount(address,uint256)',
|
||||
'eth_getTransactionByHash(bytes32)',
|
||||
'eth_getTransactionReceipt(bytes32)',
|
||||
'eth_getStorageAt(address,bytes32)',
|
||||
'eth_getStorageAt(address,bytes32,uint256)'
|
||||
]
|
||||
const ambInformationSelectors = Object.fromEntries(ambInformationSignatures.map(sig => [soliditySha3(sig), sig]))
|
||||
const normalizeAMBInfoRequest = e => ({
|
||||
messageId: e.returnValues.messageId,
|
||||
sender: e.returnValues.sender,
|
||||
requestSelector: ambInformationSelectors[e.returnValues.requestSelector] || 'unknown',
|
||||
data: e.returnValues.data
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
strip0x,
|
||||
parseAMBMessage,
|
||||
normalizeAMBMessageEvent
|
||||
normalizeAMBMessageEvent,
|
||||
ambInformationSignatures,
|
||||
normalizeAMBInfoRequest
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"gas-price-oracle": "^0.1.5",
|
||||
"web3-utils": "1.0.0-beta.34"
|
||||
"web3-utils": "^1.3.0",
|
||||
"node-fetch": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bn-chai": "^1.0.1",
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
const { expect } = require('chai')
|
||||
const { BRIDGE_MODES, ERC_TYPES } = require('../constants')
|
||||
const { BRIDGE_MODES } = require('../constants')
|
||||
|
||||
describe('constants', () => {
|
||||
it('should contain correct number of bridge types', () => {
|
||||
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(7)
|
||||
})
|
||||
|
||||
it('should contain correct number of erc types', () => {
|
||||
expect(Object.keys(ERC_TYPES).length).to.be.equal(2)
|
||||
expect(Object.keys(BRIDGE_MODES).length).to.be.equal(3)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
const { expect } = require('chai')
|
||||
const { getTokenType, ERC_TYPES } = require('..')
|
||||
|
||||
describe('getTokenType', () => {
|
||||
it('should return ERC677 if bridgeContract is equal to bridgeAddress', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(bridgeAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC677)
|
||||
})
|
||||
|
||||
it('should return ERC20 if bridgeContract is not equal to bridgeAddress', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.resolve('0xBFCb120F7B1de491262CA4D9D8Eba70438b6896E')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
|
||||
it('should return ERC20 if bridgeContract is not present', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
|
||||
it('should return ERC20 if bridgeContract and isBridge are not present', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
},
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
|
||||
it('should return ERC677 if isBridge returns true', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
},
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC677)
|
||||
})
|
||||
|
||||
it('should return ERC677 if isBridge returns true and bridgeContract not present', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC677)
|
||||
})
|
||||
|
||||
it('should return ERC20 if isBridge returns false', async () => {
|
||||
// Given
|
||||
const bridgeAddress = '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26'
|
||||
const contract = {
|
||||
methods: {
|
||||
bridgeContract: () => {
|
||||
return {
|
||||
call: () => Promise.reject()
|
||||
}
|
||||
},
|
||||
isBridge: () => {
|
||||
return {
|
||||
call: () => Promise.resolve(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
const type = await getTokenType(contract, bridgeAddress)
|
||||
|
||||
// Then
|
||||
expect(type).to.equal(ERC_TYPES.ERC20)
|
||||
})
|
||||
})
|
||||
144
commons/utils.js
144
commons/utils.js
@@ -1,22 +1,17 @@
|
||||
const { toWei, toBN } = require('web3-utils')
|
||||
const { toWei, toBN, BN } = require('web3-utils')
|
||||
const { GasPriceOracle } = require('gas-price-oracle')
|
||||
const { BRIDGE_MODES, FEE_MANAGER_MODE, ERC_TYPES } = require('./constants')
|
||||
const fetch = require('node-fetch')
|
||||
const { BRIDGE_MODES } = require('./constants')
|
||||
const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
|
||||
|
||||
const gasPriceOracle = new GasPriceOracle()
|
||||
|
||||
function decodeBridgeMode(bridgeModeHash) {
|
||||
switch (bridgeModeHash) {
|
||||
case '0x92a8d7fe':
|
||||
return BRIDGE_MODES.NATIVE_TO_ERC
|
||||
case '0xba4690f5':
|
||||
return BRIDGE_MODES.ERC_TO_ERC
|
||||
case '0x18762d46':
|
||||
return BRIDGE_MODES.ERC_TO_NATIVE
|
||||
case '0x2544fbb9':
|
||||
return BRIDGE_MODES.ARBITRARY_MESSAGE
|
||||
case '0x16ea01e9':
|
||||
return BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
case '0x76595b56':
|
||||
return BRIDGE_MODES.AMB_ERC_TO_ERC
|
||||
default:
|
||||
@@ -24,80 +19,9 @@ function decodeBridgeMode(bridgeModeHash) {
|
||||
}
|
||||
}
|
||||
|
||||
const decodeFeeManagerMode = managerModeHash => {
|
||||
switch (managerModeHash) {
|
||||
case '0xf2aed8f7':
|
||||
return FEE_MANAGER_MODE.ONE_DIRECTION
|
||||
case '0xd7de965f':
|
||||
return FEE_MANAGER_MODE.BOTH_DIRECTIONS
|
||||
default:
|
||||
throw new Error(`Unrecognized fee manager mode hash: '${managerModeHash}'`)
|
||||
}
|
||||
}
|
||||
|
||||
async function getBridgeMode(contract) {
|
||||
try {
|
||||
const bridgeModeHash = await contract.methods.getBridgeMode().call()
|
||||
return decodeBridgeMode(bridgeModeHash)
|
||||
} catch (e) {
|
||||
return BRIDGE_MODES.NATIVE_TO_ERC_V1
|
||||
}
|
||||
}
|
||||
|
||||
const getTokenType = async (bridgeTokenContract, bridgeAddress) => {
|
||||
try {
|
||||
const resultBridgeAddress = await bridgeTokenContract.methods.bridgeContract().call()
|
||||
if (resultBridgeAddress === bridgeAddress) {
|
||||
return ERC_TYPES.ERC677
|
||||
} else {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
} catch (e) {
|
||||
try {
|
||||
const isBridge = await bridgeTokenContract.methods.isBridge(bridgeAddress).call()
|
||||
if (isBridge) {
|
||||
return ERC_TYPES.ERC677
|
||||
} else {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
} catch (e) {
|
||||
return ERC_TYPES.ERC20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isErcToErcMode = bridgeMode => {
|
||||
return (
|
||||
bridgeMode === BRIDGE_MODES.ERC_TO_ERC ||
|
||||
bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC ||
|
||||
bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
)
|
||||
}
|
||||
|
||||
const isMediatorMode = bridgeMode => {
|
||||
return bridgeMode === BRIDGE_MODES.AMB_ERC_TO_ERC || bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC
|
||||
}
|
||||
|
||||
const getUnit = bridgeMode => {
|
||||
let unitHome = null
|
||||
let unitForeign = null
|
||||
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
|
||||
unitHome = 'Native coins'
|
||||
unitForeign = 'Tokens'
|
||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||
unitHome = 'Tokens'
|
||||
unitForeign = 'Tokens'
|
||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
unitHome = 'Native coins'
|
||||
unitForeign = 'Tokens'
|
||||
} else if (bridgeMode === BRIDGE_MODES.STAKE_AMB_ERC_TO_ERC) {
|
||||
unitHome = 'Tokens'
|
||||
unitForeign = 'Tokens'
|
||||
} else {
|
||||
throw new Error(`Unrecognized bridge mode: ${bridgeMode}`)
|
||||
}
|
||||
|
||||
return { unitHome, unitForeign }
|
||||
const bridgeModeHash = await contract.methods.getBridgeMode().call()
|
||||
return decodeBridgeMode(bridgeModeHash)
|
||||
}
|
||||
|
||||
const parseValidatorEvent = event => {
|
||||
@@ -150,11 +74,8 @@ const tryCall = async (method, fallbackValue) => {
|
||||
|
||||
const getDeployedAtBlock = async contract => tryCall(contract.methods.deployedAtBlock(), 0)
|
||||
|
||||
const getPastEvents = async (
|
||||
contract,
|
||||
{ event = 'allEvents', fromBlock = toBN(0), toBlock = 'latest', options = {} }
|
||||
) => {
|
||||
let events
|
||||
const getPastEventsOrSplit = async (contract, { event, fromBlock, toBlock, options }) => {
|
||||
let events = []
|
||||
try {
|
||||
events = await contract.getPastEvents(event, {
|
||||
...options,
|
||||
@@ -162,19 +83,19 @@ const getPastEvents = async (
|
||||
toBlock
|
||||
})
|
||||
} catch (e) {
|
||||
if (e.message.includes('query returned more than') && toBlock !== 'latest') {
|
||||
if (e.message.includes('query returned more than') || e.message.toLowerCase().includes('timeout')) {
|
||||
const middle = toBN(fromBlock)
|
||||
.add(toBN(toBlock))
|
||||
.divRound(toBN(2))
|
||||
const middlePlusOne = middle.add(toBN(1))
|
||||
|
||||
const firstHalfEvents = await getPastEvents(contract, {
|
||||
const firstHalfEvents = await getPastEventsOrSplit(contract, {
|
||||
options,
|
||||
event,
|
||||
fromBlock,
|
||||
toBlock: middle
|
||||
})
|
||||
const secondHalfEvents = await getPastEvents(contract, {
|
||||
const secondHalfEvents = await getPastEventsOrSplit(contract, {
|
||||
options,
|
||||
event,
|
||||
fromBlock: middlePlusOne,
|
||||
@@ -188,6 +109,31 @@ const getPastEvents = async (
|
||||
return events
|
||||
}
|
||||
|
||||
const getPastEvents = async (
|
||||
contract,
|
||||
{ event = 'allEvents', fromBlock = toBN(0), toBlock = 'latest', options = {} }
|
||||
) => {
|
||||
if (toBlock === 'latest') {
|
||||
return contract.getPastEvents(event, {
|
||||
...options,
|
||||
fromBlock,
|
||||
toBlock
|
||||
})
|
||||
}
|
||||
|
||||
const batchSize = 1000000
|
||||
const to = toBN(toBlock)
|
||||
const events = []
|
||||
|
||||
for (let from = toBN(fromBlock); from.lte(to); from = from.addn(batchSize + 1)) {
|
||||
const opts = { event, fromBlock: from, toBlock: BN.min(to, from.addn(batchSize)), options }
|
||||
const batch = await getPastEventsOrSplit(contract, opts)
|
||||
events.push(batch)
|
||||
}
|
||||
|
||||
return [].concat(...events)
|
||||
}
|
||||
|
||||
const getValidatorList = async (address, eth, options) => {
|
||||
options.logger && options.logger.debug && options.logger.debug('getting validatorList')
|
||||
|
||||
@@ -233,17 +179,16 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
|
||||
return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei'))
|
||||
}
|
||||
|
||||
// fetchFn has to be supplied (instead of just url to oracle),
|
||||
// because this utility function is shared between Browser and Node,
|
||||
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
|
||||
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
|
||||
const gasPriceFromSupplier = async (url, options = {}) => {
|
||||
try {
|
||||
let json
|
||||
if (fetchFn) {
|
||||
const response = await fetchFn()
|
||||
if (url === 'gas-price-oracle') {
|
||||
json = await gasPriceOracle.fetchGasPricesOffChain()
|
||||
} else if (url) {
|
||||
const response = await fetch(url, { timeout: 2000 })
|
||||
json = await response.json()
|
||||
} else {
|
||||
json = await gasPriceOracle.fetchGasPricesOffChain()
|
||||
return null
|
||||
}
|
||||
const oracleGasPrice = json[options.speedType]
|
||||
|
||||
@@ -284,10 +229,7 @@ const gasPriceFromContract = async (bridgeContract, options = {}) => {
|
||||
|
||||
module.exports = {
|
||||
decodeBridgeMode,
|
||||
decodeFeeManagerMode,
|
||||
getBridgeMode,
|
||||
getTokenType,
|
||||
getUnit,
|
||||
parseValidatorEvent,
|
||||
processValidatorsEvents,
|
||||
getValidatorList,
|
||||
@@ -296,7 +238,5 @@ module.exports = {
|
||||
normalizeGasPrice,
|
||||
gasPriceFromSupplier,
|
||||
gasPriceFromContract,
|
||||
gasPriceWithinLimits,
|
||||
isErcToErcMode,
|
||||
isMediatorMode
|
||||
gasPriceWithinLimits
|
||||
}
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
const homeV1Abi = [
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'validatorContract',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: false,
|
||||
name: 'recipient',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'Deposit',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: false,
|
||||
name: 'recipient',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'transactionHash',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
name: 'Withdraw',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'deployedAtBlock',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'requiredBlockConfirmations',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
|
||||
const foreignViAbi = [
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'validatorContract',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: false,
|
||||
name: 'recipient',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'transactionHash',
|
||||
type: 'bytes32'
|
||||
}
|
||||
],
|
||||
name: 'Deposit',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: false,
|
||||
name: 'recipient',
|
||||
type: 'address'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'value',
|
||||
type: 'uint256'
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
name: 'homeGasPrice',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
name: 'Withdraw',
|
||||
type: 'event'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'deployedAtBlock',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'erc677token',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'address'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
name: 'requiredBlockConfirmations',
|
||||
outputs: [
|
||||
{
|
||||
name: '',
|
||||
type: 'uint256'
|
||||
}
|
||||
],
|
||||
payable: false,
|
||||
stateMutability: 'view',
|
||||
type: 'function'
|
||||
}
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
HOME_V1_ABI: homeV1Abi,
|
||||
FOREIGN_V1_ABI: foreignViAbi
|
||||
}
|
||||
Submodule contracts updated: 835742dfd8...908a481079
@@ -1,4 +1,4 @@
|
||||
FROM python:3.7-stretch
|
||||
FROM python:3.7
|
||||
RUN curl -fsSL https://get.docker.com | sh
|
||||
RUN pip3 install docker molecule==2.22rc1 molecule[docker] flake8
|
||||
RUN pip3 install docker molecule[docker,ansible] pytest pytest-testinfra flake8
|
||||
WORKDIR mono/deployment-e2e
|
||||
|
||||
@@ -16,7 +16,7 @@ Alternatively, if there are no changes except the playbooks, you can use the `ma
|
||||
./molecule.sh <scenario_name>
|
||||
```
|
||||
|
||||
In this case `master` branch will be used as a codebase for Monitor, UI, Oracle and Contracts deployed by your local playbook.
|
||||
In this case `master` branch will be used as a codebase for Monitor, Oracle and Contracts deployed by your local playbook.
|
||||
|
||||
## Run the tests
|
||||
|
||||
@@ -29,7 +29,6 @@ Available scenarios:
|
||||
Scenario | Description
|
||||
--- | ---
|
||||
oracle | Deploys and checks standalone Oracle on Ubuntu host
|
||||
ui | Deploys and checks standalone UI on Ubuntu host
|
||||
|
||||
## Ultimate E2E tests
|
||||
|
||||
|
||||
@@ -3,12 +3,6 @@ dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: docker
|
||||
lint:
|
||||
name: yamllint
|
||||
enabled: True
|
||||
options:
|
||||
config-data:
|
||||
ignore: ../../hosts.yml
|
||||
platforms:
|
||||
- name: monitor-host
|
||||
groups:
|
||||
@@ -22,11 +16,6 @@ platforms:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
lint:
|
||||
name: ansible-lint
|
||||
enabled: True
|
||||
options:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ./converge.yml
|
||||
@@ -37,14 +26,11 @@ provisioner:
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
additional_files_or_dirs:
|
||||
- ../../tests/*
|
||||
scenario:
|
||||
name: monitor
|
||||
test_sequence:
|
||||
- lint
|
||||
- cleanup
|
||||
- destroy
|
||||
- dependency
|
||||
|
||||
@@ -3,12 +3,6 @@ dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: docker
|
||||
lint:
|
||||
name: yamllint
|
||||
enabled: True
|
||||
options:
|
||||
config-data:
|
||||
ignore: ../../hosts.yml
|
||||
platforms:
|
||||
- name: multiple-host
|
||||
groups:
|
||||
@@ -16,7 +10,6 @@ platforms:
|
||||
children:
|
||||
- oracle
|
||||
- monitor
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
@@ -24,30 +17,22 @@ platforms:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
lint:
|
||||
name: ansible-lint
|
||||
enabled: True
|
||||
options:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../monitor/converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
multiple-host:
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d"
|
||||
MONITOR_PORT: 3003
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
additional_files_or_dirs:
|
||||
- ../../tests/*
|
||||
scenario:
|
||||
name: multiple
|
||||
test_sequence:
|
||||
- lint
|
||||
- cleanup
|
||||
- destroy
|
||||
- dependency
|
||||
|
||||
@@ -8,7 +8,6 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
|
||||
@pytest.mark.parametrize("service", [
|
||||
("poabridge"),
|
||||
("tokenbridge-ui"),
|
||||
("tokenbridge-monitor")
|
||||
])
|
||||
def test_services(host, service):
|
||||
@@ -24,7 +23,7 @@ def test_services(host, service):
|
||||
("oracle_bridge_affirmation_1"),
|
||||
("oracle_bridge_senderhome_1"),
|
||||
("oracle_bridge_senderforeign_1"),
|
||||
("ui_ui_1"),
|
||||
("oracle_bridge_shutdown_1"),
|
||||
("monitor_monitor_1")
|
||||
])
|
||||
def test_docker_containers(host, name):
|
||||
|
||||
@@ -3,18 +3,12 @@ dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: docker
|
||||
lint:
|
||||
name: yamllint
|
||||
enabled: True
|
||||
options:
|
||||
config-data:
|
||||
ignore: ../../hosts.yml
|
||||
platforms:
|
||||
- name: oracle-host
|
||||
groups:
|
||||
- example
|
||||
children:
|
||||
- oracle
|
||||
- oracle_swarm
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
@@ -22,29 +16,22 @@ platforms:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
lint:
|
||||
name: ansible-lint
|
||||
enabled: True
|
||||
options:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../../../deployment/site.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-host:
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ORACLE_VALIDATOR_KEYSTORE_PATH: "../../../e2e-commons/keystore.json"
|
||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678"
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
additional_files_or_dirs:
|
||||
- ../../tests/*
|
||||
scenario:
|
||||
name: oracle
|
||||
test_sequence:
|
||||
- lint
|
||||
- cleanup
|
||||
- destroy
|
||||
- dependency
|
||||
|
||||
@@ -3,21 +3,21 @@ import pytest
|
||||
import testinfra.utils.ansible_runner
|
||||
|
||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle')
|
||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle_swarm')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", [
|
||||
("oracle_rabbit_1"),
|
||||
("oracle_redis_1"),
|
||||
("oracle_bridge_request_1"),
|
||||
("oracle_bridge_collected_1"),
|
||||
("oracle_bridge_affirmation_1"),
|
||||
("oracle_bridge_senderhome_1"),
|
||||
("oracle_bridge_senderforeign_1"),
|
||||
("oracle_rabbit"),
|
||||
("oracle_redis"),
|
||||
("oracle_bridge_request"),
|
||||
("oracle_bridge_collected"),
|
||||
("oracle_bridge_affirmation"),
|
||||
("oracle_bridge_senderhome"),
|
||||
("oracle_bridge_senderforeign"),
|
||||
("oracle_bridge_shutdown"),
|
||||
])
|
||||
def test_docker_containers(host, name):
|
||||
container = host.docker(name)
|
||||
assert container.is_running
|
||||
assert host.docker(name) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("service", [
|
||||
|
||||
@@ -15,7 +15,6 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
("/home/poadocker/bridge/contracts"),
|
||||
("/home/poadocker/bridge/oracle"),
|
||||
("/home/poadocker/bridge/monitor"),
|
||||
("/home/poadocker/bridge/ui"),
|
||||
("/home/poadocker/bridge/parity")
|
||||
])
|
||||
def test_existing_folders(host, path):
|
||||
@@ -28,8 +27,7 @@ def test_existing_folders(host, path):
|
||||
("/home/poadocker/bridge/commons/package.json"),
|
||||
("/home/poadocker/bridge/contracts/package.json"),
|
||||
("/home/poadocker/bridge/oracle/package.json"),
|
||||
("/home/poadocker/bridge/monitor/package.json"),
|
||||
("/home/poadocker/bridge/ui/package.json")
|
||||
("/home/poadocker/bridge/monitor/package.json")
|
||||
])
|
||||
def test_existing_package_json(host, path):
|
||||
assert host.file(path).exists
|
||||
@@ -41,8 +39,7 @@ def test_existing_package_json(host, path):
|
||||
("/home/poadocker/bridge/contracts/Dockerfile"),
|
||||
("/home/poadocker/bridge/parity/Dockerfile"),
|
||||
("/home/poadocker/bridge/oracle/Dockerfile"),
|
||||
("/home/poadocker/bridge/monitor/Dockerfile"),
|
||||
("/home/poadocker/bridge/ui/Dockerfile")
|
||||
("/home/poadocker/bridge/monitor/Dockerfile")
|
||||
])
|
||||
def test_existing_docker_files(host, path):
|
||||
assert host.file(path).exists
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Molecule managed
|
||||
|
||||
{% if item.registry is defined %}
|
||||
FROM {{ item.registry.url }}/{{ item.image }}
|
||||
{% else %}
|
||||
FROM {{ item.image }}
|
||||
{% endif %}
|
||||
|
||||
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
|
||||
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
|
||||
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
|
||||
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
|
||||
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
|
||||
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: docker
|
||||
lint:
|
||||
name: yamllint
|
||||
enabled: True
|
||||
options:
|
||||
config-data:
|
||||
ignore: ../../hosts.yml
|
||||
platforms:
|
||||
- name: ui-host
|
||||
groups:
|
||||
- example
|
||||
children:
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
lint:
|
||||
name: ansible-lint
|
||||
enabled: True
|
||||
options:
|
||||
r: ["bug"]
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../../../deployment/site.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
ui-host:
|
||||
syslog_server_port: "udp://127.0.0.1:514"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
additional_files_or_dirs:
|
||||
- ../../tests/*
|
||||
scenario:
|
||||
name: ui
|
||||
test_sequence:
|
||||
- lint
|
||||
- cleanup
|
||||
- destroy
|
||||
- dependency
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
- verify
|
||||
- destroy
|
||||
@@ -1,48 +0,0 @@
|
||||
import os
|
||||
import pytest
|
||||
import testinfra.utils.ansible_runner
|
||||
|
||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('ui')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", [
|
||||
("ui_ui_1")
|
||||
])
|
||||
def test_docker_containers(host, name):
|
||||
container = host.docker(name)
|
||||
assert container.is_running
|
||||
|
||||
|
||||
@pytest.mark.parametrize("service", [
|
||||
("tokenbridge-ui"),
|
||||
("rsyslog")
|
||||
])
|
||||
def test_services(host, service):
|
||||
assert host.service(service).is_enabled
|
||||
assert host.service(service).is_running
|
||||
|
||||
|
||||
@pytest.mark.parametrize("filename", [
|
||||
("/etc/rsyslog.d/32-ui-docker.conf"),
|
||||
("/etc/rsyslog.d/37-ui-remote-logging.conf")
|
||||
])
|
||||
def test_logging(host, filename):
|
||||
assert host.file(filename).exists
|
||||
assert host.file(filename).mode == 0o0644
|
||||
|
||||
|
||||
def test_index_page_title(host):
|
||||
assert host.run_test(
|
||||
'curl -s http://localhost:3001 | '
|
||||
'grep "<title>" | '
|
||||
'grep -q "TokenBridge UI app"'
|
||||
)
|
||||
|
||||
|
||||
def test_index_page_error(host):
|
||||
assert host.run_expect(
|
||||
[1],
|
||||
'curl -s http://localhost:3001 | '
|
||||
'grep -i -q "error"'
|
||||
)
|
||||
@@ -1,14 +0,0 @@
|
||||
# Molecule managed
|
||||
|
||||
{% if item.registry is defined %}
|
||||
FROM {{ item.registry.url }}/{{ item.image }}
|
||||
{% else %}
|
||||
FROM {{ item.image }}
|
||||
{% endif %}
|
||||
|
||||
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
|
||||
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
|
||||
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
|
||||
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
|
||||
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
|
||||
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: oracle-amb-host
|
||||
groups:
|
||||
- ultimate
|
||||
- amb
|
||||
children:
|
||||
- oracle
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- name: ui-amb-stake-erc-to-erc-host
|
||||
groups:
|
||||
- ultimate
|
||||
- amb-stake-erc-to-erc
|
||||
children:
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../ultimate-commons/converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-amb-host:
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-amb-stake-erc-to-erc-host:
|
||||
COMMON_HOME_RPC_URL: "http://localhost:8541"
|
||||
COMMON_FOREIGN_RPC_URL: "http://localhost:8542"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-amb-stake-erc-to-erc
|
||||
test_sequence:
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
@@ -25,8 +25,6 @@ provisioner:
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-amb
|
||||
test_sequence:
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
- oracle_net_db_bridge_request
|
||||
- oracle_net_db_bridge_collected
|
||||
- oracle_net_db_bridge_affirmation
|
||||
- oracle_net_db_bridge_information
|
||||
- oracle_net_db_bridge_transfer
|
||||
- oracle_net_db_bridge_senderhome
|
||||
- oracle_net_db_bridge_senderforeign
|
||||
- oracle_net_db_bridge_shutdown
|
||||
- oracle_net_rabbit_bridge_request
|
||||
- oracle_net_rabbit_bridge_collected
|
||||
- oracle_net_rabbit_bridge_affirmation
|
||||
- oracle_net_rabbit_bridge_information
|
||||
- oracle_net_rabbit_bridge_transfer
|
||||
- oracle_net_rabbit_bridge_senderhome
|
||||
- oracle_net_rabbit_bridge_senderforeign
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Molecule managed
|
||||
|
||||
{% if item.registry is defined %}
|
||||
FROM {{ item.registry.url }}/{{ item.image }}
|
||||
{% else %}
|
||||
FROM {{ item.image }}
|
||||
{% endif %}
|
||||
|
||||
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
|
||||
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
|
||||
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
|
||||
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
|
||||
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
|
||||
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: oracle-erc-to-erc-host
|
||||
groups:
|
||||
- ultimate
|
||||
- erc-to-erc
|
||||
children:
|
||||
- oracle
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- name: ui-erc-to-erc-host
|
||||
groups:
|
||||
- ultimate
|
||||
- erc-to-erc
|
||||
children:
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../ultimate-commons/converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-erc-to-erc-host:
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-erc-to-erc-host:
|
||||
COMMON_HOME_RPC_URL: "http://localhost:8541"
|
||||
COMMON_FOREIGN_RPC_URL: "http://localhost:8542"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-erc-to-erc
|
||||
test_sequence:
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
@@ -13,17 +13,6 @@ platforms:
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- name: ui-erc-to-native-host
|
||||
groups:
|
||||
- ultimate
|
||||
- erc-to-native
|
||||
children:
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
@@ -36,13 +25,8 @@ provisioner:
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ORACLE_HOME_START_BLOCK: 1
|
||||
ORACLE_FOREIGN_START_BLOCK: 1
|
||||
ui-erc-to-native-host:
|
||||
COMMON_HOME_RPC_URL: "http://localhost:8541"
|
||||
COMMON_FOREIGN_RPC_URL: "http://localhost:8542"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-erc-to-native
|
||||
test_sequence:
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Molecule managed
|
||||
|
||||
{% if item.registry is defined %}
|
||||
FROM {{ item.registry.url }}/{{ item.image }}
|
||||
{% else %}
|
||||
FROM {{ item.image }}
|
||||
{% endif %}
|
||||
|
||||
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
|
||||
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \
|
||||
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
|
||||
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \
|
||||
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
|
||||
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: oracle-native-to-erc-host
|
||||
groups:
|
||||
- ultimate
|
||||
- native-to-erc
|
||||
children:
|
||||
- oracle
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- name: ui-native-to-erc-host
|
||||
groups:
|
||||
- ultimate
|
||||
- native-to-erc
|
||||
children:
|
||||
- ui
|
||||
image: ubuntu:16.04
|
||||
privileged: true
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../prepare.yml
|
||||
converge: ../ultimate-commons/converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
oracle-native-to-erc-host:
|
||||
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||
ui-native-to-erc-host:
|
||||
COMMON_HOME_RPC_URL: "http://localhost:8541"
|
||||
COMMON_FOREIGN_RPC_URL: "http://localhost:8542"
|
||||
verifier:
|
||||
name: testinfra
|
||||
lint:
|
||||
name: flake8
|
||||
scenario:
|
||||
name: ultimate-native-to-erc
|
||||
test_sequence:
|
||||
- cleanup
|
||||
- destroy
|
||||
- syntax
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
@@ -34,14 +34,6 @@ cp hosts.yml.example hosts.yml
|
||||
#syslog_server_port: "<protocol>://<ip>:<port>" # When this parameter is set all bridge logs will be redirected to <ip>:<port> address.
|
||||
<host_ip_B>:
|
||||
# (...)
|
||||
ui:
|
||||
hosts:
|
||||
<host_ip_B>:
|
||||
ansible_user: <user>
|
||||
#syslog_server_port: "<protocol>://<ip>:<port>"
|
||||
<host_ip_C>:
|
||||
ansible_user: <user>
|
||||
#syslog_server_port: "<protocol>://<ip>:<port>"
|
||||
monitor:
|
||||
hosts:
|
||||
<host_ip_B>:
|
||||
@@ -50,18 +42,7 @@ cp hosts.yml.example hosts.yml
|
||||
#monitor_cron_schedule: "*/4 * * * *" # When this parameter is set, it will overwrite default schedule for performing checks
|
||||
```
|
||||
|
||||
The config above would install the Oracle on `<host_ip_A>`, UI on `<host_ip_C>`, and both Oracle, UI and Monitor on `<host_ip_B>`.
|
||||
|
||||
Example config for installing only UI:
|
||||
```yaml
|
||||
<bridge_name>:
|
||||
children:
|
||||
oracle:
|
||||
hosts:
|
||||
ui:
|
||||
hosts:
|
||||
<host_ip>:
|
||||
ansible_user: <user>
|
||||
The config above would install the Oracle on `<host_ip_A>`, and both Oracle and Monitor on `<host_ip_B>`.
|
||||
```
|
||||
|
||||
| Value | Description |
|
||||
|
||||
@@ -44,7 +44,6 @@ The deployed components have the following services:
|
||||
Component | Service Name
|
||||
--- | ---
|
||||
Oracle | poabridge
|
||||
UI | tokenbridge-ui
|
||||
Monitor | tokenbridge-monitor
|
||||
|
||||
Use the default `SysVinit` commands to `start`, `stop`, `restart`, and `rebuild` the service and to check the `status` of the service.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0xc26Aa60Ff574f157616D3aEE70e08aAC129E1dFC"
|
||||
UI_PORT: 3003
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0AEe1FCD12dDFab6265F7f8956e6E012A9Fe4Aa0"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x8397be90BCF57b0B71219f555Fe121b22e5a994C"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E"
|
||||
MONITOR_PORT: 3013
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
---
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "xDai"
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://dai.poa.network"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "xDai chain"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Ethereum Mainnet"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 5000
|
||||
|
||||
@@ -30,20 +25,6 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring MakerDAO stable tokens between the Ethereum network to xDai chain in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/dai/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/mainnet/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/dai/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "https://dai-bridge.poa.network"
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "xdai"
|
||||
MONITOR_PORT: 3003
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "ERC_TO_ERC"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x1feB40aD9420b186F019A717c37f5546165d411E"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127"
|
||||
UI_PORT: 3001
|
||||
MONITOR_PORT: 3011
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "ERC_TO_NATIVE"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x488Af810997eD1730cB3a3918cD83b3216E6eAda"
|
||||
UI_PORT: 3002
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
|
||||
MONITOR_PORT: 3012
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
---
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
ORACLE_BRIDGE_MODE: "ARBITRARY_MESSAGE"
|
||||
ORACLE_LOG_LEVEL: debug
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "POA"
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://sokol.poa.network"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x98aFdE294f1C46aA0a27Cc4049ED337F879d8976"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x59ba90A588ce732AB33FD32Aab1b58c21400A0f6"
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://sokol.poa.network"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x5a584f4C30B36f282848dAc9a2b20E7BEF481981"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
||||
COMMON_FOREIGN_RPC_URL: "https://kovan.infura.io/v3/5d7bd94c50ed43fab1cb8e74f58678b0"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0xdA4a49a00F4fF4A5988b9AceE95f99e3b2c208b6"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 5000
|
||||
|
||||
## Home Gasprice
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
@@ -32,26 +27,12 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "http://localhost:3001"
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_CACHE_EVENTS: "false"
|
||||
MONITOR_HOME_START_BLOCK: 0
|
||||
MONITOR_FOREIGN_START_BLOCK: 0
|
||||
MONITOR_HOME_START_BLOCK: 20821049
|
||||
MONITOR_FOREIGN_START_BLOCK: 24773297
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x32198D570fffC7033641F8A9094FFDCaAEF42624"
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x2B6871b9B02F73fa24F4864322CdC78604207769"
|
||||
UI_PORT: 3000
|
||||
MONITOR_PORT: 3010
|
||||
@@ -1,19 +1,14 @@
|
||||
---
|
||||
## General settings
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "POA"
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC: yes
|
||||
ORACLE_LOG_LEVEL: debug
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "http://parity1:8545"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "POA Sokol"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 5000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "http://parity2:8545"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Kovan"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 1000
|
||||
|
||||
## Home Gasprice
|
||||
@@ -30,20 +25,6 @@ COMMON_FOREIGN_GAS_PRICE_FALLBACK: 1000000000 # in wei
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
|
||||
|
||||
#ui
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The POA cross-chain bridge serves as a method of transferring POA native tokens from the POA Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/poa/sokol/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/kovan/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/poa/sokol/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/kovan/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "core"
|
||||
UI_PUBLIC_URL: "http://localhost"
|
||||
|
||||
#monitor
|
||||
MONITOR_BRIDGE_NAME: "bridge"
|
||||
MONITOR_CACHE_EVENTS: "true"
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE: "NATIVE_TO_ERC"
|
||||
UI_NATIVE_TOKEN_DISPLAY_NAME: "ETC"
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL: "https://www.ethercluster.com/etc"
|
||||
UI_HOME_NETWORK_DISPLAY_NAME: "Ethereum Classic"
|
||||
UI_HOME_WITHOUT_EVENTS: false
|
||||
COMMON_HOME_BRIDGE_ADDRESS: "0x073081832B4Ecdce79d4D6753565c85Ba4b3BeA9"
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL: 7000
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL: "https://mainnet.infura.io/"
|
||||
UI_FOREIGN_NETWORK_DISPLAY_NAME: "Ethereum Mainnet"
|
||||
UI_FOREIGN_WITHOUT_EVENTS: false
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS: "0x0cB781EE62F815bdD9CD4c2210aE8600d43e7040"
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL: 7000
|
||||
|
||||
## Home Gasprice
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL: "https://gasprice-etc.poa.network/"
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK: 15000000000 # in wei
|
||||
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
COMMON_HOME_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## Foreign Gasprice
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL: "https://gasprice.poa.network/"
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE: "standard"
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK: 10000000000 # in wei
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR: 1
|
||||
|
||||
## UI
|
||||
UI_TITLE: "TokenBridge UI app - %c"
|
||||
UI_OG_TITLE: "POA Bridge UI"
|
||||
UI_DESCRIPTION: "The TokenBridge serves as a method of transferring native tokens from the Ethereum Classic Network to the Ethereum network in a quick and cost-efficient manner."
|
||||
UI_PORT: 3001
|
||||
UI_HOME_EXPLORER_TX_TEMPLATE: https://blockscout.com/etc/mainnet/tx/%s
|
||||
UI_FOREIGN_EXPLORER_TX_TEMPLATE: https://blockscout.com/eth/mainnet/tx/%s
|
||||
UI_HOME_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/etc/mainnet/address/%s
|
||||
UI_FOREIGN_EXPLORER_ADDRESS_TEMPLATE: https://blockscout.com/eth/mainnet/address/%s
|
||||
UI_HOME_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_FOREIGN_GAS_PRICE_UPDATE_INTERVAL: 600000
|
||||
UI_STYLES: "classic"
|
||||
UI_PUBLIC_URL: "https://wetc.app"
|
||||
|
||||
## Monitor
|
||||
MONITOR_BRIDGE_NAME: "wetc"
|
||||
MONITOR_PORT: 3003
|
||||
MONITOR_CACHE_EVENTS: "true"
|
||||
MONITOR_HOME_START_BLOCK: 7703292
|
||||
MONITOR_FOREIGN_START_BLOCK: 7412459
|
||||
MONITOR_VALIDATOR_HOME_TX_LIMIT: 300000
|
||||
MONITOR_VALIDATOR_FOREIGN_TX_LIMIT: 300000
|
||||
MONITOR_TX_NUMBER_THRESHOLD: 100
|
||||
@@ -7,10 +7,12 @@ sokol-kovan:
|
||||
ansible_user: ubuntu
|
||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
#syslog_server_port: "udp://127.0.0.1:514"
|
||||
ui:
|
||||
oracle_swarm:
|
||||
hosts:
|
||||
127.0.0.1:
|
||||
ansible_user: ubuntu
|
||||
ORACLE_VALIDATOR_KEYSTORE_PATH: "/path/to/keystore.json"
|
||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678"
|
||||
#syslog_server_port: "udp://127.0.0.1:514"
|
||||
monitor:
|
||||
hosts:
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# pre-release because it contains "CI Fixes for ansible 2.8"
|
||||
molecule==2.22rc1
|
||||
docker
|
||||
flake8
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"live-restore": true,
|
||||
"live-restore": false,
|
||||
"no-new-privileges": true
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0755"
|
||||
when: skip_compose is undefined
|
||||
|
||||
- name: Upgrade pip version
|
||||
shell: pip3 install --upgrade pip==19.3.1
|
||||
@@ -45,6 +46,9 @@
|
||||
group: docker
|
||||
createhome: yes
|
||||
|
||||
- name: reset ssh connection to allow user changes to affect ansible user
|
||||
meta: reset_connection
|
||||
|
||||
- name: Install auditd
|
||||
apt:
|
||||
name: auditd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/var/log/docker/*/docker.log {
|
||||
rotate 5
|
||||
size 1G
|
||||
size 100M
|
||||
compress
|
||||
missingok
|
||||
delaycompress
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
/var/log/docker/*.log {
|
||||
rotate 5
|
||||
size 1G
|
||||
size 100M
|
||||
compress
|
||||
missingok
|
||||
delaycompress
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
with_items:
|
||||
- docker-compose
|
||||
- docker-compose-transfer
|
||||
- docker-compose-erc-native
|
||||
- docker-compose-amb
|
||||
loop_control:
|
||||
loop_var: file
|
||||
|
||||
- name: Set the local container logs configuration file
|
||||
- name: Set the oracle's containers local logs configuration file
|
||||
template:
|
||||
src: 31-oracle-docker.conf.j2
|
||||
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
||||
@@ -15,6 +15,22 @@
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: Set the redis container local logs configuration file
|
||||
template:
|
||||
src: 32-redis-docker.conf.j2
|
||||
dest: /etc/rsyslog.d/32-redis-docker.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: Set the rabbit MQ container local logs configuration file
|
||||
template:
|
||||
src: 33-rabbit-docker.conf.j2
|
||||
dest: /etc/rsyslog.d/33-rabbit-docker.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: Set the log configuration file to send container logs to remote server
|
||||
template:
|
||||
src: 36-oracle-remote-logging.conf.j2
|
||||
|
||||
@@ -27,25 +27,14 @@
|
||||
set_fact:
|
||||
ORACLE_VALIDATOR_ADDRESS: "{{ VADDRESS.stdout }}"
|
||||
|
||||
- name: Get foreign erc type
|
||||
become_user: "{{ compose_service_user }}"
|
||||
shell: docker-compose run --rm --entrypoint "node scripts/initialChecks.js" bridge_affirmation
|
||||
args:
|
||||
chdir: "{{ bridge_path }}/oracle"
|
||||
register: ERCTYPE
|
||||
|
||||
- name: Set FOREIGN_ERC_TYPE variable
|
||||
set_fact:
|
||||
FOREIGN_ERC_TYPE: "{{ (ERCTYPE.stdout).foreignERC | default('') }}"
|
||||
|
||||
- name: Extend docker compose file
|
||||
set_fact: composefileoverride="-f docker-compose-transfer.yml"
|
||||
when: ORACLE_BRIDGE_MODE == "ERC_TO_ERC" and FOREIGN_ERC_TYPE != "ERC677"
|
||||
|
||||
- name: Extend docker compose file for erc to native
|
||||
set_fact: composefileoverride="-f docker-compose-erc-native.yml"
|
||||
set_fact: composefileoverride="-f docker-compose-transfer.yml"
|
||||
when: ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE"
|
||||
|
||||
- name: Extend docker compose file for amb
|
||||
set_fact: composefileoverride="-f docker-compose-amb.yml"
|
||||
when: ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE"
|
||||
|
||||
- name: Install .key config
|
||||
template:
|
||||
src: key.j2
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
with_items:
|
||||
- docker-compose.yml
|
||||
- docker-compose-transfer.yml
|
||||
- docker-compose-erc-native.yml
|
||||
- docker-compose-amb.yml
|
||||
|
||||
@@ -11,9 +11,16 @@ ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }}
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
||||
{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %}
|
||||
ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }}
|
||||
{% endif %}
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
||||
|
||||
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
||||
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
||||
{% endif %}
|
||||
|
||||
## Gasprice
|
||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
||||
@@ -47,8 +54,28 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
||||
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
||||
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
||||
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
||||
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
||||
{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %}
|
||||
ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %}
|
||||
ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }}
|
||||
{% endif %}
|
||||
|
||||
## Emergency shutdown configuration
|
||||
{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SIDE_RPC_URL | default('') != '' %}
|
||||
ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }}
|
||||
{% endif %}
|
||||
|
||||
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
||||
|
||||
11
deployment/roles/oracle/templates/32-redis-docker.conf.j2
Normal file
11
deployment/roles/oracle/templates/32-redis-docker.conf.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
$FileCreateMode 0644
|
||||
template(name="DockerLogFileName_Redis" type="list") {
|
||||
constant(value="/var/log/docker/")
|
||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
|
||||
constant(value="/docker.log")
|
||||
}
|
||||
|
||||
if $programname contains 'oracle' and $programname contains 'redis' then \
|
||||
?DockerLogFileName_Redis
|
||||
|
||||
$FileCreateMode 0600
|
||||
11
deployment/roles/oracle/templates/33-rabbit-docker.conf.j2
Normal file
11
deployment/roles/oracle/templates/33-rabbit-docker.conf.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
$FileCreateMode 0644
|
||||
template(name="DockerLogFileName_Rabbit" type="list") {
|
||||
constant(value="/var/log/docker/")
|
||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
|
||||
constant(value="/docker.log")
|
||||
}
|
||||
|
||||
if $programname contains 'oracle' and $programname contains 'rabbit' then \
|
||||
?DockerLogFileName_Rabbit
|
||||
|
||||
$FileCreateMode 0600
|
||||
9
deployment/roles/oracle_swarm/defaults/main.yml
Normal file
9
deployment/roles/oracle_swarm/defaults/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
bridge_path: "/home/{{ compose_service_user }}/bridge"
|
||||
bridge_data_path: "/home/{{ compose_service_user }}/bridge_data"
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC: no
|
||||
ORACLE_QUEUE_URL: amqp://rabbit
|
||||
ORACLE_REDIS_URL: redis://redis
|
||||
keyfile_path: "/root/.key"
|
||||
keystore_path: "/root/.keystore.json"
|
||||
oracle_image: poanetwork/tokenbridge-oracle:latest
|
||||
3
deployment/roles/oracle_swarm/meta/main.yml
Normal file
3
deployment/roles/oracle_swarm/meta/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
dependencies:
|
||||
- { role: common, skip_repo: true, skip_compose: true }
|
||||
8
deployment/roles/oracle_swarm/tasks/jumpbox.yml
Normal file
8
deployment/roles/oracle_swarm/tasks/jumpbox.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Pull the containers images
|
||||
community.docker.docker_image:
|
||||
name: "{{ oracle_image }}"
|
||||
source: pull
|
||||
when: skip_pull is undefined
|
||||
vars:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
41
deployment/roles/oracle_swarm/tasks/logging.yml
Normal file
41
deployment/roles/oracle_swarm/tasks/logging.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
- name: Set the oracle's containers local logs configuration file
|
||||
template:
|
||||
src: 31-oracle-docker.conf.j2
|
||||
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: Set the redis container local logs configuration file
|
||||
template:
|
||||
src: 32-redis-docker.conf.j2
|
||||
dest: /etc/rsyslog.d/32-redis-docker.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: Set the rabbit MQ container local logs configuration file
|
||||
template:
|
||||
src: 33-rabbit-docker.conf.j2
|
||||
dest: /etc/rsyslog.d/33-rabbit-docker.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: Set the log configuration file to send container logs to remote server
|
||||
template:
|
||||
src: 36-oracle-remote-logging.conf.j2
|
||||
dest: /etc/rsyslog.d/36-oracle-remote-logging.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
when: syslog_server_port is defined
|
||||
|
||||
- name: Discarding unwanted messages in rsyslog
|
||||
blockinfile:
|
||||
path: /etc/rsyslog.conf
|
||||
insertbefore: "# Where to place spool and state files"
|
||||
marker: "#{mark} add string to discarding unwanted messages"
|
||||
content: ':msg, contains, "ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY" ~'
|
||||
notify: restart rsyslog
|
||||
@@ -2,4 +2,5 @@
|
||||
- include_tasks: pre_config.yml
|
||||
- include_tasks: logging.yml
|
||||
- include_tasks: jumpbox.yml
|
||||
- include_tasks: post_config.yml
|
||||
- include_tasks: servinstall.yml
|
||||
46
deployment/roles/oracle_swarm/tasks/post_config.yml
Normal file
46
deployment/roles/oracle_swarm/tasks/post_config.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
- name: Get blocks
|
||||
become_user: "{{ compose_service_user }}"
|
||||
shell: docker run --env-file .env --rm {{ oracle_image }} scripts/getValidatorStartBlocks.js
|
||||
args:
|
||||
chdir: "{{ bridge_path }}/oracle"
|
||||
register: BLOCKS
|
||||
when: (ORACLE_HOME_START_BLOCK is not defined) or (ORACLE_FOREIGN_START_BLOCK is not defined)
|
||||
|
||||
- name: Write blocks
|
||||
blockinfile:
|
||||
path: "{{ bridge_path }}/oracle/.env"
|
||||
marker: "## {mark} Calculated by scripts/getValidatorStartBlocks.js"
|
||||
block: |
|
||||
ORACLE_HOME_START_BLOCK={{ (BLOCKS.stdout | from_json).homeStartBlock }}
|
||||
ORACLE_FOREIGN_START_BLOCK={{ (BLOCKS.stdout | from_json).foreignStartBlock }}
|
||||
when: (ORACLE_HOME_START_BLOCK is not defined) or (ORACLE_FOREIGN_START_BLOCK is not defined)
|
||||
|
||||
- name: Copy keystore file
|
||||
copy:
|
||||
src: "{{ ORACLE_VALIDATOR_KEYSTORE_PATH }}"
|
||||
dest: "{{ keystore_path }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0600
|
||||
|
||||
- name: Create swarm secret
|
||||
community.docker.docker_secret:
|
||||
name: oracle_keystore
|
||||
state: present
|
||||
data_src: "{{ keystore_path }}"
|
||||
vars:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
|
||||
- name: Remove unencrypted keystore file
|
||||
file:
|
||||
path: "{{ keystore_path }}"
|
||||
state: absent
|
||||
|
||||
- name: Install .key config
|
||||
template:
|
||||
src: key.j2
|
||||
dest: "{{ keyfile_path }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0600
|
||||
47
deployment/roles/oracle_swarm/tasks/pre_config.yml
Normal file
47
deployment/roles/oracle_swarm/tasks/pre_config.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
- name: Init docker swarm
|
||||
community.docker.docker_swarm:
|
||||
state: present
|
||||
autolock_managers: yes
|
||||
listen_addr: 127.0.0.1:2377
|
||||
vars:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
|
||||
- name: Get unlock token
|
||||
community.docker.docker_swarm_info:
|
||||
unlock_key: yes
|
||||
register: result
|
||||
vars:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
|
||||
- name: Print unlock token
|
||||
debug:
|
||||
var: result.swarm_unlock_key
|
||||
|
||||
- name: Create oracle directory
|
||||
file:
|
||||
path: "{{ bridge_path }}/oracle"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Create rabbitmq directory
|
||||
file:
|
||||
path: "{{ bridge_data_path }}/{{ item }}"
|
||||
state: directory
|
||||
mode: '0775'
|
||||
loop:
|
||||
- rabbitmq
|
||||
- redis
|
||||
|
||||
- name: Install .env config
|
||||
template:
|
||||
src: .env.j2
|
||||
dest: "{{ bridge_path }}/oracle/.env"
|
||||
owner: "{{ compose_service_user }}"
|
||||
mode: '0640'
|
||||
|
||||
- name: Install docker-compose file
|
||||
template:
|
||||
src: docker-compose.yml.j2
|
||||
dest: "{{ bridge_path }}/oracle/docker-compose.yml"
|
||||
mode: '0755'
|
||||
19
deployment/roles/oracle_swarm/tasks/servinstall.yml
Normal file
19
deployment/roles/oracle_swarm/tasks/servinstall.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
# This role creates a poabridge service which is designed to manage docker-compose bridge deployment.
|
||||
# /etc/init.d/poabridge start, status, stop, restart - does what the services usually do in such cases.
|
||||
---
|
||||
- name: "Set poabridge service"
|
||||
template:
|
||||
src: poabridge.j2
|
||||
dest: "/etc/init.d/poabridge"
|
||||
owner: root
|
||||
mode: 755
|
||||
|
||||
- name: "Enable the service"
|
||||
service:
|
||||
name: "poabridge"
|
||||
state: started
|
||||
enabled: yes
|
||||
use: service
|
||||
|
||||
- name: Start the service
|
||||
shell: service poabridge start
|
||||
86
deployment/roles/oracle_swarm/templates/.env.j2
Normal file
86
deployment/roles/oracle_swarm/templates/.env.j2
Normal file
@@ -0,0 +1,86 @@
|
||||
## General settings
|
||||
ORACLE_BRIDGE_MODE={{ ORACLE_BRIDGE_MODE }}
|
||||
{% if ORACLE_LOG_LEVEL | default('') != '' %}
|
||||
ORACLE_LOG_LEVEL={{ ORACLE_LOG_LEVEL }}
|
||||
{% endif %}
|
||||
|
||||
## Home contract
|
||||
COMMON_HOME_RPC_URL={{ COMMON_HOME_RPC_URL }}
|
||||
COMMON_HOME_BRIDGE_ADDRESS={{ COMMON_HOME_BRIDGE_ADDRESS }}
|
||||
ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }}
|
||||
|
||||
## Foreign contract
|
||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
||||
{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %}
|
||||
ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }}
|
||||
{% endif %}
|
||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
||||
|
||||
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
||||
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
||||
{% endif %}
|
||||
|
||||
## Gasprice
|
||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
||||
{% endif %}
|
||||
{% if COMMON_HOME_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE={{ COMMON_HOME_GAS_PRICE_SPEED_TYPE }}
|
||||
{% endif %}
|
||||
COMMON_HOME_GAS_PRICE_FALLBACK={{ COMMON_HOME_GAS_PRICE_FALLBACK }}
|
||||
{% if ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
|
||||
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL={{ ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL }}
|
||||
{% endif %}
|
||||
{% if COMMON_HOME_GAS_PRICE_FACTOR | default('') != '' %}
|
||||
COMMON_HOME_GAS_PRICE_FACTOR={{ COMMON_HOME_GAS_PRICE_FACTOR }}
|
||||
{% endif %}
|
||||
|
||||
{% if COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL={{ COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL }}
|
||||
{% endif %}
|
||||
{% if COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE={{ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE }}
|
||||
{% endif %}
|
||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK={{ COMMON_FOREIGN_GAS_PRICE_FALLBACK }}
|
||||
{% if ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
|
||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL }}
|
||||
{% endif %}
|
||||
{% if COMMON_FOREIGN_GAS_PRICE_FACTOR | default('') != '' %}
|
||||
COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
||||
{% endif %}
|
||||
|
||||
## Transport configuration
|
||||
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
||||
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
||||
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
||||
{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %}
|
||||
ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %}
|
||||
ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }}
|
||||
{% endif %}
|
||||
|
||||
## Emergency shutdown configuration
|
||||
{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SIDE_RPC_URL | default('') != '' %}
|
||||
ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }}
|
||||
{% endif %}
|
||||
{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %}
|
||||
ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }}
|
||||
{% endif %}
|
||||
|
||||
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
||||
ORACLE_HOME_START_BLOCK={{ ORACLE_HOME_START_BLOCK }}
|
||||
{% endif %}
|
||||
{% if ORACLE_FOREIGN_START_BLOCK | default('') != '' %}
|
||||
ORACLE_FOREIGN_START_BLOCK={{ ORACLE_FOREIGN_START_BLOCK }}
|
||||
{% endif %}
|
||||
@@ -0,0 +1,11 @@
|
||||
$FileCreateMode 0644
|
||||
template(name="DockerLogFileName_Oracle" type="list") {
|
||||
constant(value="/var/log/docker/")
|
||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="bridge_(.*)\\/[a-zA-Z0-9]+\\[")
|
||||
constant(value="/docker.log")
|
||||
}
|
||||
|
||||
if $programname startswith 'oracle_bridge_' then \
|
||||
?DockerLogFileName_Oracle
|
||||
|
||||
$FileCreateMode 0600
|
||||
@@ -0,0 +1,11 @@
|
||||
$FileCreateMode 0644
|
||||
template(name="DockerLogFileName_Redis" type="list") {
|
||||
constant(value="/var/log/docker/")
|
||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
|
||||
constant(value="/docker.log")
|
||||
}
|
||||
|
||||
if $programname contains 'oracle' and $programname contains 'redis' then \
|
||||
?DockerLogFileName_Redis
|
||||
|
||||
$FileCreateMode 0600
|
||||
@@ -0,0 +1,11 @@
|
||||
$FileCreateMode 0644
|
||||
template(name="DockerLogFileName_Rabbit" type="list") {
|
||||
constant(value="/var/log/docker/")
|
||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
|
||||
constant(value="/docker.log")
|
||||
}
|
||||
|
||||
if $programname contains 'oracle' and $programname contains 'rabbit' then \
|
||||
?DockerLogFileName_Rabbit
|
||||
|
||||
$FileCreateMode 0600
|
||||
@@ -1,4 +1,4 @@
|
||||
if $programname startswith 'ui_' then {
|
||||
if $programname startswith 'oracle_bridge_' then {
|
||||
action(
|
||||
type="omfwd"
|
||||
protocol="{{ syslog_server_port.split(":")[0] }}"
|
||||
144
deployment/roles/oracle_swarm/templates/docker-compose.yml.j2
Normal file
144
deployment/roles/oracle_swarm/templates/docker-compose.yml.j2
Normal file
@@ -0,0 +1,144 @@
|
||||
version: '3.9'
|
||||
x-deploy: &x-deploy
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.3'
|
||||
memory: 500M
|
||||
reservations:
|
||||
memory: 100M
|
||||
x-keystore-access: &x-keystore-access
|
||||
environment:
|
||||
ORACLE_VALIDATOR_KEYSTORE_PATH: /run/secrets/oracle_keystore
|
||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD:
|
||||
secrets:
|
||||
- oracle_keystore
|
||||
x-logging: &x-logging
|
||||
driver: 'syslog'
|
||||
options: {tag: '{{ '{{.Name}}/{{.ID}}' }}' }
|
||||
services:
|
||||
rabbit:
|
||||
image: rabbitmq:3
|
||||
hostname: rabbit
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
environment: [ 'RABBITMQ_NODENAME=node@rabbit' ]
|
||||
networks:
|
||||
- net_rabbit_bridge_request
|
||||
- net_rabbit_bridge_collected
|
||||
- net_rabbit_bridge_affirmation
|
||||
- net_rabbit_bridge_senderhome
|
||||
- net_rabbit_bridge_senderforeign
|
||||
volumes: [ '{{ bridge_data_path }}/rabbitmq:/var/lib/rabbitmq/mnesia' ]
|
||||
redis:
|
||||
image: redis:4
|
||||
hostname: redis
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
command: [ redis-server, --appendonly, 'yes' ]
|
||||
networks:
|
||||
- net_db_bridge_request
|
||||
- net_db_bridge_collected
|
||||
- net_db_bridge_affirmation
|
||||
- net_db_bridge_senderhome
|
||||
- net_db_bridge_senderforeign
|
||||
- net_db_bridge_shutdown
|
||||
volumes: [ '{{ bridge_data_path }}/redis:/data' ]
|
||||
bridge_request:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
env_file: ./.env
|
||||
<<: *x-keystore-access
|
||||
entrypoint: yarn watcher:signature-request
|
||||
networks:
|
||||
- net_db_bridge_request
|
||||
- net_rabbit_bridge_request
|
||||
bridge_collected:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
env_file: ./.env
|
||||
entrypoint: yarn watcher:collected-signatures
|
||||
networks:
|
||||
- net_db_bridge_collected
|
||||
- net_rabbit_bridge_collected
|
||||
bridge_affirmation:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
env_file: ./.env
|
||||
entrypoint: yarn watcher:affirmation-request
|
||||
networks:
|
||||
- net_db_bridge_affirmation
|
||||
- net_rabbit_bridge_affirmation
|
||||
bridge_senderhome:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
env_file: ./.env
|
||||
<<: *x-keystore-access
|
||||
entrypoint: yarn sender:home
|
||||
networks:
|
||||
- net_db_bridge_senderhome
|
||||
- net_rabbit_bridge_senderhome
|
||||
bridge_senderforeign:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
env_file: ./.env
|
||||
<<: *x-keystore-access
|
||||
entrypoint: yarn sender:foreign
|
||||
networks:
|
||||
- net_db_bridge_senderforeign
|
||||
- net_rabbit_bridge_senderforeign
|
||||
bridge_shutdown:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
env_file: ./.env
|
||||
entrypoint: yarn manager:shutdown
|
||||
networks:
|
||||
- net_db_bridge_shutdown
|
||||
{% if ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" %}
|
||||
bridge_transfer:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
env_file: ./.env
|
||||
entrypoint: yarn watcher:transfer
|
||||
networks:
|
||||
- net_db_bridge_transfer
|
||||
- net_rabbit_bridge_transfer
|
||||
{% endif %}
|
||||
{% if ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" %}
|
||||
bridge_information:
|
||||
image: {{ oracle_image }}
|
||||
deploy: *x-deploy
|
||||
logging: *x-logging
|
||||
env_file: ./.env
|
||||
entrypoint: yarn watcher:information-request
|
||||
networks:
|
||||
- net_db_bridge_information
|
||||
- net_rabbit_bridge_information
|
||||
{% endif %}
|
||||
networks:
|
||||
net_db_bridge_request:
|
||||
net_db_bridge_collected:
|
||||
net_db_bridge_affirmation:
|
||||
net_db_bridge_senderhome:
|
||||
net_db_bridge_senderforeign:
|
||||
net_db_bridge_shutdown:
|
||||
{% if ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" %}
|
||||
net_db_bridge_transfer:
|
||||
net_rabbit_bridge_transfer:
|
||||
{% endif %}
|
||||
{% if ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" %}
|
||||
net_db_bridge_information:
|
||||
net_rabbit_bridge_information:
|
||||
{% endif %}
|
||||
net_rabbit_bridge_request:
|
||||
net_rabbit_bridge_collected:
|
||||
net_rabbit_bridge_affirmation:
|
||||
net_rabbit_bridge_senderhome:
|
||||
net_rabbit_bridge_senderforeign:
|
||||
|
||||
secrets:
|
||||
oracle_keystore:
|
||||
external: true
|
||||
2
deployment/roles/oracle_swarm/templates/key.j2
Normal file
2
deployment/roles/oracle_swarm/templates/key.j2
Normal file
@@ -0,0 +1,2 @@
|
||||
## Validator-specific options
|
||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD={{ ORACLE_VALIDATOR_KEYSTORE_PASSWORD }}
|
||||
66
deployment/roles/oracle_swarm/templates/poabridge.j2
Normal file
66
deployment/roles/oracle_swarm/templates/poabridge.j2
Normal file
@@ -0,0 +1,66 @@
|
||||
#! /bin/bash
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: poabridge
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start daemon at boot time
|
||||
# Description: Enable service provided by daemon.
|
||||
### END INIT INFO
|
||||
|
||||
WORKDIR="{{ '/home/' + compose_service_user | default('poadocker') + '/' + bridge_path + '/oracle' if bridge_path[:1] != "/" else bridge_path + '/oracle' }}"
|
||||
|
||||
#Getting path to private key file and variable name for parsing key file
|
||||
source {{ keyfile_path }}
|
||||
|
||||
start(){
|
||||
echo "Starting bridge.."
|
||||
cd $WORKDIR
|
||||
sudo -u "{{ compose_service_user }}" docker stack rm oracle
|
||||
sudo -u "{{ compose_service_user }}" "ORACLE_VALIDATOR_KEYSTORE_PASSWORD=$ORACLE_VALIDATOR_KEYSTORE_PASSWORD" docker stack deploy oracle -c docker-compose.yml
|
||||
}
|
||||
|
||||
stop(){
|
||||
echo "Stopping bridge.."
|
||||
cd $WORKDIR
|
||||
sudo -u "{{ compose_service_user }}" docker stack rm oracle
|
||||
sleep 2
|
||||
}
|
||||
|
||||
status(){
|
||||
echo "Bridge status:"
|
||||
cd $WORKDIR
|
||||
sudo -u "{{ compose_service_user }}" docker service ls
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
|
||||
start)
|
||||
start
|
||||
;;
|
||||
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
|
||||
status)
|
||||
status
|
||||
;;
|
||||
|
||||
restart)
|
||||
echo "Restarting bridge.."
|
||||
stop
|
||||
start
|
||||
;;
|
||||
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -1,3 +0,0 @@
|
||||
---
|
||||
dependencies:
|
||||
- role: common
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
- name: Build the containers
|
||||
shell: docker-compose build
|
||||
args:
|
||||
chdir: "{{ bridge_path }}/ui"
|
||||
when: skip_build is undefined
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user