Skip to content

Instantly share code, notes, and snippets.

@phahulin
Last active November 16, 2019 17:05
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save phahulin/3e64ec9ff553f5eb85ff09170b79540b to your computer and use it in GitHub Desktop.
SCD to MCD bridge

The new releases containing the changes related to the Phase 1 of the migration have been prepared:

  • TokenBridge contracts - 3.2.0
  • TokenBridge node - 1.1.0

The following steps should be done as part of the procedure to migrate the xDai bridge from SCD tokens to MCD in the phase 1:

  1. Discover if any MCD transfer to the bridge contract happened, write down the block where the first such transfer happened.
  2. The bridge administrators must initiate and complete signing on the xDai chain for the invocation of the setMaxPerTx method with 0 value. Starting from this point the oracles will relay only deposit requests for SCD tokens. setMaxPerTx ABI:
{"constant":false,"inputs":[{"name":"_maxPerTx","type":"uint256"}],"name":"setMaxPerTx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}
  1. Deploy new implementation of the bridge contract on the Mainnet Ethereum.
  2. The bridge upgradability administrators must initiate and complete signing on the Mainnet Ethereum for the invocation of the upgradeTo (or upgradeAndCall if the feature "Relative daily limits" is included in the new implementation) method. At this point users must be still able to deposit SCD tokens'.
  3. Stop all oracles on every validator node. Starting from this point users will be able initiate SCD transfers to the bridge contracts, but they will not be relayed.
  4. Deploy new implementation of the bridge contract on the xDai chain if it is necessary to include security fixes and enhancements (e.g. the feature "Relative daily limits").
  5. If the step 6 is applicable, the bridge upgradability administrators must initiate and complete signing on the xDai chain for the invocation of the upgradeTo (or upgradeAndCall) method.
  6. Upgrade oracles on every validator node. (checkout the branch!!! clone --recursive!!!)
  7. Run the oracles on the validators nodes. Starting from this point the oracles will handle all deposit requests postponed after the step 5.
  8. The bridge administrators must initiate and complete signing on the Ethereum Mainnet chain for the invocation of the migrateToMCD method with addresses of the migration and MCD contracts. Make sure that no oracles are restarted after step 9 since they still serve deposit requests for SCD.
  9. Stop all oracles on every validator node.
  10. Compare the last block numbers observed by every oracle to find a minimal one. Reset the last observed block to the comparison result. If there is any transaction found on the step 1 use the block number that includes this transaction.
  11. Run the oracles on the validators nodes. Starting from this point the oracles will handle all existing deposit requests for MCD tokens.
  12. The bridge administrators must initiate and complete signing on the xDai chain for the invocation of the setMaxPerTx method with an initial value. Starting from this point the oracles handle all withdrawal requests and unlock MCD tokens.
  13. If there is any not relayed transfer request for SCD token in the Ethereum Mainnet after the step 11, the the bridge upgradability administrators must initiate and complete signing for claimTokens to refund SCD tokens to the initial owners.
// npm install web3@1.2.4
const Web3 = require('web3');
const RPC_ENDPOINT = 'https://kovan.infura.io'; /// CHANGE THIS
const web3 = new Web3(RPC_ENDPOINT);
/// CHANGE THIS
const MCD_DAI = {
address: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa',
deployment_block: 14764537,
abi: [{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "src",
"type": "address",
},
{
"indexed": true,
"internalType": "address",
"name": "dst",
"type": "address",
},
{
"indexed": false,
"internalType": "uint256",
"name": "wad",
"type": "uint256",
}
],
"name": "Transfer",
"type": "event",
}],
};
const BRIDGE_ETH = {
address: '0x87881f415fBC924b7d80FB67646704bDFBB0293d', /// CHANGE THIS TO 0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016
};
async function main() {
let contract = new web3.eth.Contract(MCD_DAI.abi, MCD_DAI.address);
let opts = {
fromBlock: MCD_DAI.deployment_block,
filter: { dst: BRIDGE_ETH.address },
};
let events = await contract.getPastEvents('Transfer', opts);
let earlies_block = 99999999;
for (let e of events) {
console.log(`${e.blockNumber} ${e.transactionHash}: ${e.returnValues.src} -> ${e.returnValues.dst} for ${e.returnValues.wad}`);
if (Number(e.blockNumber) < earlies_block) {
earlies_block = Number(e.blockNumber);
}
}
console.log(`----------------`);
console.log(`${events.length} events total. Earliest at block ${earlies_block}.`);
}
main();

Dear validators,

to prepare for the migration, please launch new servers with new version of the bridge validator oracle.

Upgrade procedure

In short, the following procedure looks like this:

  • create new server, check connection
  • stop bridge oracle on the current server
  • get last block numbers processed by the current server
  • run ansible playbook on the new server and provide it with values from previous step, so that new service would start where current one stopped

In more details:

  1. Create a new server instance with your hosting provider (e.g. AWS, Digital Ocean, etc), you can use same specs as the current one (or at least 2 Core CPU, 4 GB RAM, Ubuntu 16.04 LTS, 32 GB Disk). Important: don't stop or terminate your current server yet! If you're currently running both xDai bridge validator and xDai network validator on the same server, let us know and, after bridge migration is complete, we'll provide you with instructions on how to move network validator on your new server.

  2. When you created new server, please note down its' IP address and try to connect to it via ssh from your local computer to make sure that the server is accessible to you. When connected to the server, check that your user has sudo-privileges by running

sudo hostname

It should complete without asking for password or any other errors. Please note down your server's hostname so that we could identify it later.

  1. Installation procedure involves running an ansible playbook from your local computer. Ansible will connect to new server, install required dependencies, code of the oracle and start bridge service. To use ansible, you first need to install required dependencies and ansible itself, please take a look at https://github.com/poanetwork/tokenbridge/blob/1.1.0/deployment/EXECUTION.md#dependencies

  2. After all the prerequisites are installed, download code of the new oracle to your local computer and switch to version 1.1.0

git clone --recursive https://github.com/poanetwork/tokenbridge
cd tokenbridge
git checkout 1.1.0
cd deployment
  1. Make sure you ended up in the correct folder
pwd

output should end with .../tokenbridge/deployment. And on the correct branch

git branch

output should be similar to

* (HEAD detached at 1.1.0)
  master

note where the * is.

  1. Now connect to your current bridge validator node.

  2. Stop bridge docker containers:

sudo docker ps -q -f "name=bridge_bridge" | xargs sudo docker stop
  1. Connect to redis container:
sudo docker exec -it bridge_redis_1 /bin/bash

A new shell should appear, which is a shell running inside redis docker container. Shell prompt should look similar to this:

root@redis:/data#
  1. Connect to redis database via cli
redis-cli

shell prompt should change one more time to something like this:

127.0.0.1:6379>
  1. Get the list of all entries in the database:
keys *

You should get output similar to this one:

1) "erc-native-signature-request:lastProcessedBlock"
2) "erc-native-collected-signatures:lastProcessedBlock"
3) "foreign:nonce"
4) "home:nonce"
5) "erc-native-affirmation-request:lastProcessedBlock"
  1. Run the following commands one-by-one to get current values of all *:lastProcessedBlock entries and copy the output somewhere, because we'll need it later
get "erc-native-affirmation-request:lastProcessedBlock"
get "erc-native-collected-signatures:lastProcessedBlock"
get "erc-native-signature-request:lastProcessedBlock"
  1. remove entries containing nonces:
del "home:nonce"
del "foreign:nonce"
  1. Run exit twice to get out of both the redis cli shell and redis container shell. You should now be back to the bash prompt on your current server.

  2. Stop current bridge service altogether

sudo service poabridge stop
  1. Run exit to close connection and return to your local computer. You should still be in the .../tokenbridge/deployment folder

  2. Create and open hosts.yml configuration file in your favourite text editor (I'll be using nano as an example):

nano hosts.yml

Paste the following into this file

---
dai:
  children:
    oracle:
      hosts:
        1.1.1.1:
          ansible_user: ubuntu
          ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "PASTE YOUR PRIVATE KEY HERE"
          syslog_server_port: "udp://logs5.papertrailapp.com:33240"
          ORACLE_HOME_START_BLOCK: 0000000
          ORACLE_FOREIGN_START_BLOCK: 0000000

Please check that whitespaces were pasted correctly!

  1. Set values of the following configuration options:
  • 1.1.1.1: replace it with real IP address of your new server
  • ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: your private key (this value must be 64 characters long)
  • ORACLE_HOME_START_BLOCK: compare values you got from redis for erc-native-collected-signatures:lastProcessedBlock and erc-native-signature-request:lastProcessedBlock, they are most likely equal or differ by 1. You should use the smallest of the two.
  • ORACLE_FOREIGN_START_BLOCK: use value from erc-native-affirmation-request:lastProcessedBlock

Save the file and exit text editor (in nano: press CTRL+X then Y)

  1. Launch the playbook
ansible-playbook -i hosts.yml site.yml

Playbook should complete without errors. In this a case new oracle service will be started automatically and upgrade procedure is finished, let us know in the comments below that procedure is complete and post your new server's hostname so that we check bridge operations

In case there were any errors, post error message in the comments and follow the rollback procedure below to disable bridge service on new server and restart it on the initial server:

Rollback procedure

  1. Connect to your new server to stop docker containers and bridge service
sudo docker ps -q | xargs sudo docker stop
sudo service poabridge stop
  1. Connect to your initial server and start bridge service back:
sudo service poabridge start

This should restore bridge operations.

Multisig

https://gist.github.com/phahulin/c9a648d99273c67e7ae142d93a2bc028

Network Contract Address Blockscout Etherscan
xDai 0x0d3726e5a9f37234d6b55216fc971d30f150a60f Blockscout N/A
Eth mainnet 0xff1a8EDA5eAcdB6aAf729905492bdc6376DBe2dd Blockscout Etherscan
  • Owners:
Party Bridge validator address
POA 0x9ad83402c19af24f76afa1930a2b2eec2f47a8c5
Protofire 0x4d1c96b9a49c4469a0b720a22b74b034eddfe051
Giveth 0xc073C8E5ED9Aa11CF6776C69b3e13b259Ba9F506
MakerDAO 0x491FC792e78CDadd7D31446Bb7bDDef876a69AD6

Current bridge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment