From 38e96b5552928bc3227ccadcc73a925b0cd0769d Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Thu, 14 Nov 2019 13:28:43 +0300 Subject: [PATCH] Contract support of closing epoch process on binance side --- src/deploy/deploy-home/.env.development | 2 + src/deploy/deploy-home/.env.staging | 2 + src/deploy/deploy-home/contracts/Bridge.sol | 72 ++++++++++++++++--- .../deploy-home/migrations/1_deployment.js | 5 +- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/deploy/deploy-home/.env.development b/src/deploy/deploy-home/.env.development index 38ec3e0..7c3f528 100644 --- a/src/deploy/deploy-home/.env.development +++ b/src/deploy/deploy-home/.env.development @@ -15,3 +15,5 @@ MIN_TX_LIMIT=10000000000000000 MAX_TX_LIMIT=100000000000000000000 BLOCKS_RANGE_SIZE=10 + +CLOSE_EPOCH_FLAG=true diff --git a/src/deploy/deploy-home/.env.staging b/src/deploy/deploy-home/.env.staging index 2988dc3..7fdaf13 100644 --- a/src/deploy/deploy-home/.env.staging +++ b/src/deploy/deploy-home/.env.staging @@ -16,3 +16,5 @@ MIN_TX_LIMIT=10000000000000000 MAX_TX_LIMIT=100000000000000000000 BLOCKS_RANGE_SIZE=25 + +CLOSE_EPOCH_FLAG=true diff --git a/src/deploy/deploy-home/contracts/Bridge.sol b/src/deploy/deploy-home/contracts/Bridge.sol index 63ce4e1..cdd3f7f 100644 --- a/src/deploy/deploy-home/contracts/Bridge.sol +++ b/src/deploy/deploy-home/contracts/Bridge.sol @@ -5,6 +5,8 @@ import './openzeppelin-solidity/contracts/token/ERC20/IERC20.sol'; contract Bridge { event ExchangeRequest(uint value, uint nonce); event EpochEnd(uint indexed epoch); + event EpochClose(uint indexed epoch); + event ForceSign(); event NewEpoch(uint indexed oldEpoch, uint indexed newEpoch); event NewEpochCancelled(uint indexed epoch); event NewFundsTransfer(uint indexed oldEpoch, uint indexed newEpoch); @@ -19,10 +21,12 @@ contract Bridge { uint nonce; uint x; uint y; + bool closeEpoch; } enum Status { READY, // bridge is in ready to perform operations + CLOSING_EPOCH, // generating transaction for blocking binance side of the bridge VOTING, // voting for changing in next epoch, but still ready KEYGEN, //keygen, can be cancelled FUNDS_TRANSFER // funds transfer, cannot be cancelled @@ -31,11 +35,13 @@ contract Bridge { enum Vote { CONFIRM_KEYGEN, CONFIRM_FUNDS_TRANSFER, + CONFIRM_CLOSE_EPOCH, START_VOTING, ADD_VALIDATOR, REMOVE_VALIDATOR, CHANGE_THRESHOLD, CHANGE_RANGE_SIZE, + CHANGE_CLOSE_EPOCH, START_KEYGEN, CANCEL_KEYGEN, TRANSFER @@ -57,7 +63,7 @@ contract Bridge { uint minTxLimit; uint maxTxLimit; - constructor(uint threshold, address[] memory validators, address _tokenContract, uint[2] memory limits, uint rangeSize) public { + constructor(uint threshold, address[] memory validators, address _tokenContract, uint[2] memory limits, uint rangeSize, bool closeEpoch) public { require(validators.length > 0); require(threshold <= validators.length); @@ -72,11 +78,12 @@ contract Bridge { threshold : threshold, rangeSize : rangeSize, startBlock : 0, - endBlock : uint(-1), - nonce : uint(-1), + endBlock : uint(- 1), + nonce : uint(- 1), x : 0, - y : 0 - }); + y : 0, + closeEpoch : closeEpoch + }); minTxLimit = limits[0]; maxTxLimit = limits[1]; @@ -91,8 +98,13 @@ contract Bridge { _; } - modifier readyOrVoting { - require(status == Status.READY || status == Status.VOTING, "Not in ready or voting state"); + modifier closingEpoch { + require(status == Status.CLOSING_EPOCH, "Not in closing epoch state"); + _; + } + + modifier readyOrClosing { + require(status == Status.READY || status == Status.CLOSING_EPOCH, "Not in ready or closing epoch state"); _; } @@ -101,6 +113,11 @@ contract Bridge { _; } + modifier readyOrVoting { + require(status == Status.READY || status == Status.VOTING, "Not in ready or voting state"); + _; + } + modifier keygen { require(status == Status.KEYGEN, "Not in keygen state"); _; @@ -129,7 +146,7 @@ contract Bridge { emit ExchangeRequest(value, getNonce()); } - function transfer(bytes32 hash, address to, uint value) public readyOrVoting currentValidator { + function transfer(bytes32 hash, address to, uint value) public readyOrClosing currentValidator { if (tryVote(Vote.TRANSFER, hash, to, value)) { tokenContract.transfer(to, value); } @@ -161,12 +178,19 @@ contract Bridge { if (tryConfirm(Vote.CONFIRM_FUNDS_TRANSFER)) { status = Status.READY; states[nextEpoch].startBlock = block.number; - states[nextEpoch].nonce = uint(-1); + states[nextEpoch].nonce = uint(- 1); epoch = nextEpoch; emit EpochStart(epoch, getX(), getY()); } } + function confirmCloseEpoch() public closingEpoch currentValidator { + if (tryConfirm(Vote.CONFIRM_CLOSE_EPOCH)) { + status = Status.VOTING; + emit EpochEnd(epoch); + } + } + function getParties() view public returns (uint) { return getParties(epoch); } @@ -227,6 +251,18 @@ contract Bridge { return states[epoch].y; } + function getCloseEpoch() view public returns (bool) { + return getCloseEpoch(epoch); + } + + function getNextCloseEpoch() view public returns (bool) { + return getCloseEpoch(nextEpoch); + } + + function getCloseEpoch(uint _epoch) view public returns (bool) { + return states[_epoch].closeEpoch; + } + function getPartyId() view public returns (uint) { address[] memory validators = getValidators(); for (uint i = 0; i < getParties(); i++) { @@ -256,13 +292,21 @@ contract Bridge { function startVoting() public readyOrVoting currentValidator { if (tryVote(Vote.START_VOTING, epoch)) { nextEpoch++; - status = Status.VOTING; states[nextEpoch].endBlock = block.number; states[nextEpoch].threshold = getThreshold(); states[nextEpoch].validators = getValidators(); states[nextEpoch].rangeSize = getRangeSize(); + states[nextEpoch].closeEpoch = getCloseEpoch(); - emit EpochEnd(epoch); + if (status == Status.READY && getCloseEpoch()) { + status = Status.CLOSING_EPOCH; + emit ForceSign(); + emit EpochClose(epoch); + } else { + status = Status.VOTING; + emit ForceSign(); + emit EpochEnd(epoch); + } } } @@ -307,6 +351,12 @@ contract Bridge { } } + function voteChangeCloseEpoch(bool closeEpoch) public voting currentValidator { + if (tryVote(Vote.CHANGE_CLOSE_EPOCH, closeEpoch ? 1 : 0)) { + states[nextEpoch].closeEpoch = closeEpoch; + } + } + function voteStartKeygen() public voting currentValidator { require(getNextThreshold() <= getNextParties(), "Invalid threshold number"); diff --git a/src/deploy/deploy-home/migrations/1_deployment.js b/src/deploy/deploy-home/migrations/1_deployment.js index fe88868..05984da 100644 --- a/src/deploy/deploy-home/migrations/1_deployment.js +++ b/src/deploy/deploy-home/migrations/1_deployment.js @@ -5,7 +5,7 @@ const addresses = Object.entries(process.env) .map(([, value]) => value) const { - THRESHOLD, HOME_TOKEN_ADDRESS, MIN_TX_LIMIT, MAX_TX_LIMIT, BLOCKS_RANGE_SIZE + THRESHOLD, HOME_TOKEN_ADDRESS, MIN_TX_LIMIT, MAX_TX_LIMIT, BLOCKS_RANGE_SIZE, CLOSE_EPOCH_FLAG } = process.env module.exports = (deployer) => { @@ -15,6 +15,7 @@ module.exports = (deployer) => { addresses, HOME_TOKEN_ADDRESS, [MIN_TX_LIMIT, MAX_TX_LIMIT], - BLOCKS_RANGE_SIZE + BLOCKS_RANGE_SIZE, + CLOSE_EPOCH_FLAG === 'true' ) }