Separate queue for exchange messages. Moved nonce, rangeStart, rangeSize to bridge contract

This commit is contained in:
Kirill Fedoseev 2019-10-18 13:38:42 +03:00
parent 2e67857eff
commit 5b18ee4179
17 changed files with 173 additions and 105 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@ demo/validator*/staging
demo/validator*/.keys.staging
demo/ganache_home_db/
demo/ganache_side_db/
demo/*.zip
src/deploy/deploy-home/build/
src/deploy/deploy-side/build/
src/deploy/deploy-test/build/

View File

@ -144,15 +144,13 @@ function waitApi (n, url, check) {
function prefundEthAddresses () {
for (let { ethAddress } of userAccounts) {
exec(4, `./src/test-services/ethereumSend/run.sh ${ethAddress} 100`)
wait(4)
execSync(4, `./src/test-services/ethereumSend/run.sh ${ethAddress} 100`)
}
}
function prefundBncAddresses () {
for (let { bncAddress } of userAccounts) {
exec(4, `./src/test-services/binanceSend/run.sh ${bncAddress} 100 0.1`)
wait(4)
execSync(4, `./src/test-services/binanceSend/run.sh ${bncAddress} 100 0.1`)
}
}
@ -236,8 +234,7 @@ function testEthToBnc () {
})
userAccounts.forEach((account, i) => {
exec(4, `PRIVATE_KEY=${account.privateKey} ./src/test-services/ethereumSend/run.sh bridge ${5 + i}`)
wait(4)
execSync(4, `PRIVATE_KEY=${account.privateKey} ./src/test-services/ethereumSend/run.sh bridge ${5 + i}`)
account.ethBalance -= 5 + i
})
@ -264,8 +261,7 @@ function testBncToEth () {
})
userAccounts.forEach((account , i) => {
exec(4, `PRIVATE_KEY=${account.privateKey} ./src/test-services/binanceSend/run.sh ${bridgeBncAddress} ${3 + i}`)
wait(4)
execSync(4, `PRIVATE_KEY=${account.privateKey} ./src/test-services/binanceSend/run.sh ${bridgeBncAddress} ${3 + i}`)
account.bncBalance -= 3 + i
})

View File

@ -21,7 +21,7 @@ start_dev_blockchain_networks() {
docker kill ganache_side > /dev/null 2>&1 || true
docker network create blockchain_side > /dev/null 2>&1 || true
docker run -d --network blockchain_side --rm --name ganache_side -v "$SIDE_GANACHE_DB:/app/db" \
-p "8545:8545" \
-p "7545:8545" \
trufflesuite/ganache-cli:latest \
-m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 33 -q --db /app/db -b 3 --noVMErrorsOnRPCResponse
@ -30,6 +30,7 @@ start_dev_blockchain_networks() {
docker kill ganache_home > /dev/null 2>&1 || true
docker network create blockchain_home > /dev/null 2>&1 || true
docker run -d --network blockchain_home --rm --name ganache_home -v "$HOME_GANACHE_DB:/app/db" \
-p "8545:8545" \
trufflesuite/ganache-cli:latest \
-m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 44 -q --db /app/db -b 3 --noVMErrorsOnRPCResponse

View File

@ -3,8 +3,6 @@ HOME_BRIDGE_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
HOME_TOKEN_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
HOME_START_BLOCK=1
BLOCKS_RANGE_SIZE=25
SIDE_RPC_URL=http://ganache_side:8545
SIDE_SHARED_DB_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc

View File

@ -3,8 +3,6 @@ HOME_BRIDGE_ADDRESS=0x6ADCa5e691341fb9de8927d15c0a89B83A4E665e
HOME_TOKEN_ADDRESS=0x57d2533B640cfb58f8f1F69C14c089968Da9fdFc
HOME_START_BLOCK=13276224
BLOCKS_RANGE_SIZE=10
SIDE_RPC_URL=https://sokol.poa.network
SIDE_SHARED_DB_ADDRESS=0xda9a1cA2Fcb18cAB02934269369627D2b4ea8902

View File

@ -3,8 +3,6 @@ HOME_BRIDGE_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
HOME_TOKEN_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
HOME_START_BLOCK=1
BLOCKS_RANGE_SIZE=25
SIDE_RPC_URL=http://ganache_side:8545
SIDE_SHARED_DB_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc

View File

@ -3,8 +3,6 @@ HOME_BRIDGE_ADDRESS=0x6ADCa5e691341fb9de8927d15c0a89B83A4E665e
HOME_TOKEN_ADDRESS=0x57d2533B640cfb58f8f1F69C14c089968Da9fdFc
HOME_START_BLOCK=13276224
BLOCKS_RANGE_SIZE=10
SIDE_RPC_URL=https://sokol.poa.network
SIDE_SHARED_DB_ADDRESS=0xda9a1cA2Fcb18cAB02934269369627D2b4ea8902

View File

@ -3,8 +3,6 @@ HOME_BRIDGE_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
HOME_TOKEN_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc
HOME_START_BLOCK=1
BLOCKS_RANGE_SIZE=25
SIDE_RPC_URL=http://ganache_side:8545
SIDE_SHARED_DB_ADDRESS=0xd5fE0D28e058D375b0b038fFbB446Da37E85fFdc

View File

@ -3,8 +3,6 @@ HOME_BRIDGE_ADDRESS=0x6ADCa5e691341fb9de8927d15c0a89B83A4E665e
HOME_TOKEN_ADDRESS=0x57d2533B640cfb58f8f1F69C14c089968Da9fdFc
HOME_START_BLOCK=13276224
BLOCKS_RANGE_SIZE=10
SIDE_RPC_URL=https://sokol.poa.network
SIDE_SHARED_DB_ADDRESS=0xda9a1cA2Fcb18cAB02934269369627D2b4ea8902

View File

@ -13,3 +13,5 @@ THRESHOLD=1
MIN_TX_LIMIT=10000000000000000
MAX_TX_LIMIT=100000000000000000000
BLOCKS_RANGE_SIZE=25

View File

@ -14,3 +14,5 @@ THRESHOLD=1
MIN_TX_LIMIT=10000000000000000
MAX_TX_LIMIT=100000000000000000000
BLOCKS_RANGE_SIZE=25

View File

@ -3,7 +3,7 @@ pragma solidity ^0.5.0;
import './openzeppelin-solidity/contracts/token/ERC20/IERC20.sol';
contract Bridge {
event ExchangeRequest(uint value);
event ExchangeRequest(uint value, uint nonce);
event NewEpoch(uint indexed oldEpoch, uint indexed newEpoch);
event NewEpochCancelled(uint indexed epoch);
event NewFundsTransfer(uint indexed oldEpoch, uint indexed newEpoch);
@ -12,6 +12,9 @@ contract Bridge {
struct State {
address[] validators;
uint threshold;
uint rangeSize;
uint startBlock;
uint nonce;
uint x;
uint y;
}
@ -30,6 +33,7 @@ contract Bridge {
ADD_VALIDATOR,
REMOVE_VALIDATOR,
CHANGE_THRESHOLD,
CHANGE_RANGE_SIZE,
START_KEYGEN,
CANCEL_KEYGEN,
TRANSFER
@ -41,6 +45,7 @@ contract Bridge {
mapping(bytes32 => bool) public dbTransfer;
mapping(bytes32 => uint) public votesCount;
mapping(bytes32 => bool) public votes;
mapping(bytes32 => bool) public usedRange;
Status public status;
@ -50,7 +55,7 @@ contract Bridge {
uint minTxLimit;
uint maxTxLimit;
constructor(uint threshold, address[] memory validators, address _tokenContract, uint[2] memory limits) public {
constructor(uint threshold, address[] memory validators, address _tokenContract, uint[2] memory limits, uint rangeSize) public {
require(validators.length > 0);
require(threshold < validators.length);
@ -60,7 +65,7 @@ contract Bridge {
status = Status.KEYGEN;
nextEpoch = 1;
states[1] = State(validators, threshold, 0, 0);
states[nextEpoch] = State(validators, threshold, rangeSize, 0, uint(-1), 0, 0);
minTxLimit = limits[0];
maxTxLimit = limits[1];
@ -103,8 +108,14 @@ contract Bridge {
function exchange(uint value) public ready {
require(value >= minTxLimit && value >= 10 ** 10 && value <= maxTxLimit);
uint txRange = (block.number - getStartBlock()) / getRangeSize();
if (!usedRange[keccak256(abi.encodePacked(txRange, epoch))]) {
usedRange[keccak256(abi.encodePacked(txRange, epoch))] = true;
states[epoch].nonce++;
}
tokenContract.transferFrom(msg.sender, address(this), value);
emit ExchangeRequest(value);
emit ExchangeRequest(value, getNonce());
}
function transfer(bytes32 hash, address to, uint value) public readyOrVoting currentValidator {
@ -121,6 +132,8 @@ contract Bridge {
states[nextEpoch].y = y;
if (nextEpoch == 1) {
status = Status.READY;
states[nextEpoch].startBlock = block.number;
states[nextEpoch].nonce = uint(-1);
epoch = nextEpoch;
emit EpochStart(epoch, x, y);
}
@ -136,8 +149,10 @@ contract Bridge {
if (tryConfirm(Vote.CONFIRM_FUNDS_TRANSFER)) {
status = Status.READY;
states[nextEpoch].startBlock = block.number;
states[nextEpoch].nonce = uint(-1);
epoch = nextEpoch;
emit EpochStart(epoch, states[epoch].x, states[epoch].y);
emit EpochStart(epoch, getX(), getY());
}
}
@ -165,6 +180,34 @@ contract Bridge {
return states[_epoch].threshold;
}
function getStartBlock() view public returns (uint) {
return getStartBlock(epoch);
}
function getStartBlock(uint _epoch) view public returns (uint) {
return states[_epoch].startBlock;
}
function getRangeSize() view public returns (uint) {
return getRangeSize(epoch);
}
function getNextRangeSize() view public returns (uint) {
return getRangeSize(nextEpoch);
}
function getRangeSize(uint _epoch) view public returns (uint) {
return states[_epoch].rangeSize;
}
function getNonce() view public returns (uint) {
return getNonce(epoch);
}
function getNonce(uint _epoch) view public returns (uint) {
return states[_epoch].nonce;
}
function getX() view public returns (uint) {
return states[epoch].x;
}
@ -203,8 +246,9 @@ contract Bridge {
if (tryVote(Vote.START_VOTING)) {
nextEpoch++;
status = Status.VOTING;
states[nextEpoch].threshold = states[epoch].threshold;
states[nextEpoch].validators = states[epoch].validators;
states[nextEpoch].threshold = getThreshold();
states[nextEpoch].validators = getValidators();
states[nextEpoch].rangeSize = getRangeSize();
}
}
@ -227,7 +271,7 @@ contract Bridge {
function _removeValidator(address validator) private {
for (uint i = 0; i < getNextParties() - 1; i++) {
if (states[nextEpoch].validators[i] == validator) {
states[nextEpoch].validators[i] = states[nextEpoch].validators[getNextParties() - 1];
states[nextEpoch].validators[i] = getNextValidators()[getNextParties() - 1];
break;
}
}
@ -241,6 +285,12 @@ contract Bridge {
}
}
function voteChangeRangeSize(uint rangeSize) public voting currentValidator {
if (tryVote(Vote.CHANGE_RANGE_SIZE, rangeSize)) {
states[nextEpoch].rangeSize = rangeSize;
}
}
function voteStartKeygen() public voting currentValidator {
if (tryVote(Vote.START_KEYGEN)) {
status = Status.KEYGEN;

View File

@ -5,7 +5,7 @@ const addresses = Object.entries(process.env)
.map(([ , value ]) => value)
const {
THRESHOLD, HOME_TOKEN_ADDRESS, MIN_TX_LIMIT, MAX_TX_LIMIT
THRESHOLD, HOME_TOKEN_ADDRESS, MIN_TX_LIMIT, MAX_TX_LIMIT, BLOCKS_RANGE_SIZE
} = process.env
module.exports = deployer => {
@ -14,6 +14,7 @@ module.exports = deployer => {
THRESHOLD,
addresses,
HOME_TOKEN_ADDRESS,
[ MIN_TX_LIMIT, MAX_TX_LIMIT ]
[ MIN_TX_LIMIT, MAX_TX_LIMIT ],
BLOCKS_RANGE_SIZE
)
}

View File

@ -11,7 +11,6 @@ const { publicKeyToAddress } = require('./crypto')
const abiBridge = require('./contracts_data/Bridge.json').abi
const { HOME_RPC_URL, HOME_BRIDGE_ADDRESS, RABBITMQ_URL, HOME_START_BLOCK } = process.env
const BLOCKS_RANGE_SIZE = parseInt(process.env.BLOCKS_RANGE_SIZE)
const web3Home = new Web3(HOME_RPC_URL)
const bridge = new web3Home.eth.Contract(abiBridge, HOME_BRIDGE_ADDRESS)
@ -25,9 +24,8 @@ let blockNumber
let foreignNonce = []
let epoch
let epochStart
let rangeStart
let rangeEnd
let redisTx
let rangeSize
let lastTransactionBlockNumber
async function resetFutureMessages (queue) {
@ -84,6 +82,7 @@ async function initialize () {
if (epochStart > saved) {
logger.info(`Data in db is outdated, starting from epoch ${epoch}, block #${epochStart}`)
blockNumber = epochStart
rangeSize = (await bridge.methods.getRangeSize().call()).toNumber()
await redis.multi()
.set('homeBlock', blockNumber - 1)
.set(`foreignNonce${epoch}`, 0)
@ -95,11 +94,6 @@ async function initialize () {
foreignNonce[epoch] = parseInt(await redis.get(`foreignNonce${epoch}`)) || 0
}
rangeStart = blockNumber - (blockNumber - epochStart) % BLOCKS_RANGE_SIZE
rangeEnd = rangeStart + BLOCKS_RANGE_SIZE - 1
logger.info('Initialized sign range range, [%d-%d]', rangeStart, rangeEnd)
await resetFutureMessages(keygenQueue)
await resetFutureMessages(cancelKeygenQueue)
await resetFutureMessages(exchangeQueue)
@ -140,24 +134,22 @@ async function main () {
break
case 'EpochStart':
epoch = event.returnValues.epoch.toNumber()
epochStart = blockNumber
logger.info(`Epoch ${epoch} started`)
rangeStart = blockNumber
rangeEnd = blockNumber + BLOCKS_RANGE_SIZE - 1
logger.info('Updated sign range range, [%d-%d]', rangeStart, rangeEnd)
rangeSize = (await bridge.methods.getRangeSize().call()).toNumber()
logger.info(`Updated range size to ${rangeSize}`)
foreignNonce[epoch] = 0
break
}
}
if (blockNumber === rangeEnd) {
if ((blockNumber + 1 - epochStart) % rangeSize === 0) {
logger.info('Reached end of the current block range')
if (lastTransactionBlockNumber >= rangeStart) {
if (lastTransactionBlockNumber > blockNumber - rangeSize) {
logger.info('Sending message to start signature generation for the ended range')
await sendStartSign()
}
rangeStart = rangeEnd + 1
rangeEnd = rangeEnd + BLOCKS_RANGE_SIZE
logger.info('Updated sign range range, [%d-%d]', rangeStart, rangeEnd)
}
blockNumber++
@ -228,7 +220,8 @@ async function sendSign (event) {
x: publicKey.substr(4, 64),
y: publicKey.substr(68, 64)
}),
value: (new BN(event.returnValues.value)).dividedBy(10 ** 18).toFixed(8, 3)
value: (new BN(event.returnValues.value)).dividedBy(10 ** 18).toFixed(8, 3),
nonce: event.returnValues.nonce.toNumber()
}
exchangeQueue.send(msgToQueue)
@ -239,14 +232,15 @@ async function sendSign (event) {
logger.debug('Set lastTransactionBlockNumber to %d', blockNumber)
}
async function sendStartSign() {
async function sendStartSign () {
redisTx.incr(`foreignNonce${epoch}`)
exchangeQueue.send({
stub: true
})
signQueue.send({
epoch,
blockNumber,
nonce: foreignNonce[epoch]++,
startBlock: rangeStart,
endBlock: rangeEnd,
threshold: (await bridge.methods.getThreshold(epoch).call()).toNumber(),
parties: (await bridge.methods.getParties(epoch).call()).toNumber()
})

View File

@ -152,7 +152,7 @@ async function signupSign (req, res) {
logger.debug('SignupSign call')
const hash = sideWeb3.utils.sha3(`0x${req.body.third}`)
const query = sharedDb.methods.signupSign(hash)
const txHash = await sideSendQuery(query)
const { txHash } = await sideSendQuery(query)
const receipt = await waitForReceipt(SIDE_RPC_URL, txHash)
// Already have signup
@ -220,9 +220,26 @@ function parseError (message) {
return result ? result[0] : ''
}
async function sendVote (query, req, res) {
async function sendVote (query, req, res, waitFlag = false) {
try {
if (await homeSendQuery(query)) {
let { txHash, gasLimit } = await homeSendQuery(query)
if (txHash) {
while (waitFlag) {
const { status, gasUsed } = await waitForReceipt(HOME_RPC_URL, txHash)
if (status === '0x1') {
logger.debug('Receipt status is OK')
break
}
if (gasLimit === gasUsed) {
logger.info('Sending vote failed due to out of gas revert, retrying with more gas')
const nexTx = await homeSendQuery(query)
txHash = nexTx.txHash
gasLimit = nexTx.gasLimit
} else {
logger.warn(`Vote tx was reverted, txHash ${txHash}`)
break
}
}
res.send('Voted\n')
logger.info('Voted successfully')
} else {
@ -237,7 +254,7 @@ async function sendVote (query, req, res) {
async function voteStartVoting (req, res) {
logger.info('Voting for starting new epoch voting process')
const query = bridge.methods.startVoting()
sendVote(query, req, res)
sendVote(query, req, res, true)
}
async function voteStartKeygen (req, res) {
@ -267,7 +284,7 @@ async function voteChangeThreshold (req, res) {
async function voteRemoveValidator (req, res) {
logger.info('Voting for removing validator')
const query = bridge.methods.voteRemoveValidator(req.params.validator)
sendVote(query, req, res)
sendVote(query, req, res, true)
}
function decodeStatus (status) {
@ -283,43 +300,53 @@ function decodeStatus (status) {
}
}
function boundX(x) {
try {
return x.toNumber()
} catch (e) {
return -1
}
}
async function info (req, res) {
logger.debug('Info start')
try {
const [ x, y, epoch, nextEpoch, threshold, nextThreshold, validators, nextValidators, homeBalance, status ] = await Promise.all([
const [ x, y, epoch, rangeSize, nextRangeSize, epochStartBlock, foreignNonce, nextEpoch, threshold, nextThreshold, validators, nextValidators, status, homeBalance ] = await Promise.all([
bridge.methods.getX().call().then(x => new BN(x).toString(16)),
bridge.methods.getY().call().then(x => new BN(x).toString(16)),
bridge.methods.epoch().call().then(x => x.toNumber()),
bridge.methods.getRangeSize().call().then(x => x.toNumber()),
bridge.methods.getNextRangeSize().call().then(x => x.toNumber()),
bridge.methods.getStartBlock().call().then(x => x.toNumber()),
bridge.methods.getNonce().call().then(boundX),
bridge.methods.nextEpoch().call().then(x => x.toNumber()),
bridge.methods.getThreshold().call().then(x => x.toNumber()),
bridge.methods.getNextThreshold().call().then(x => x.toNumber()),
bridge.methods.getValidators().call(),
bridge.methods.getNextValidators().call(),
token.methods.balanceOf(HOME_BRIDGE_ADDRESS).call().then(x => parseFloat(new BN(x).dividedBy(10 ** 18).toFixed(8, 3))),
bridge.methods.status().call()
bridge.methods.status().call(),
token.methods.balanceOf(HOME_BRIDGE_ADDRESS).call().then(x => parseFloat(new BN(x).dividedBy(10 ** 18).toFixed(8, 3)))
])
const boundX = x => {
try {
return x.toNumber()
} catch (e) {
return -1
}
}
const [ confirmationsForFundsTransfer, votesForVoting, votesForKeygen, votesForCancelKeygen ] = await Promise.all([
bridge.methods.votesCount(homeWeb3.utils.sha3(utils.solidityPack([ 'uint8', 'uint256' ], [ 1, nextEpoch ]))).call().then(boundX),
bridge.methods.votesCount(homeWeb3.utils.sha3(utils.solidityPack([ 'uint8', 'uint256' ], [ 2, nextEpoch ]))).call().then(boundX),
bridge.methods.votesCount(homeWeb3.utils.sha3(utils.solidityPack([ 'uint8', 'uint256' ], [ 6, nextEpoch ]))).call().then(boundX),
bridge.methods.votesCount(homeWeb3.utils.sha3(utils.solidityPack([ 'uint8', 'uint256' ], [ 7, nextEpoch ]))).call().then(boundX)
bridge.methods.votesCount(homeWeb3.utils.sha3(utils.solidityPack([ 'uint8', 'uint256' ], [ 7, nextEpoch ]))).call().then(boundX),
bridge.methods.votesCount(homeWeb3.utils.sha3(utils.solidityPack([ 'uint8', 'uint256' ], [ 8, nextEpoch ]))).call().then(boundX)
])
const foreignAddress = publicKeyToAddress({ x, y })
const balances = await getForeignBalances(foreignAddress)
res.send({
epoch,
rangeSize,
nextRangeSize,
epochStartBlock,
nextEpoch,
threshold,
nextThreshold,
homeBridgeAddress: HOME_BRIDGE_ADDRESS,
foreignBridgeAddress: foreignAddress,
foreignNonce,
validators,
nextValidators,
homeBalance,
@ -332,7 +359,7 @@ async function info (req, res) {
confirmationsForFundsTransfer
})
} catch (e) {
res.send({message: 'Something went wrong, resend request'})
res.send({ message: 'Something went wrong, resend request', error: e })
}
logger.debug('Info end')
}
@ -344,8 +371,6 @@ async function transfer (req, res) {
logger.info(`Calling transfer to ${to}, ${value} tokens`)
const query = bridge.methods.transfer(hash, to, '0x' + (new BN(value).toString(16)))
await homeSendQuery(query)
} else {
// return funds ?
}
res.send()
logger.info('Transfer end')

View File

@ -68,7 +68,7 @@ async function createSender (url, privateKey) {
return false
}
return result
return { txHash: result, gasLimit: tx.gasLimit }
} catch (e) {
logger.warn('Something failed, %o', e)
return false
@ -80,7 +80,7 @@ async function waitForReceipt (url, txHash) {
while (true) {
const { result, error } = await sendRpcRequest(url, 'eth_getTransactionReceipt', [ txHash ])
if(result === null || error) {
if (result === null || error) {
await new Promise(res => setTimeout(res, 1000))
} else {
return result

View File

@ -45,7 +45,7 @@ async function main () {
const data = JSON.parse(msg.content)
logger.info('Consumed sign event: %o', data)
const { nonce, epoch, newEpoch, startBlock, endBlock, parties, threshold } = data
const { nonce, epoch, newEpoch, parties, threshold } = data
const keysFile = `/keys/keys${epoch}.store`
const { address: from, publicKey } = getAccountFromFile(keysFile)
@ -61,33 +61,41 @@ async function main () {
attempt = 1
if (!newEpoch && account.sequence <= nonce) {
while (true) {
logger.info(`Building corresponding transfer transaction, nonce ${nonce}`)
if (!newEpoch) {
const exchanges = await getExchangeMessages()
const exchangesData = exchanges.map(msg => JSON.parse(msg.content))
if (exchangesData.some(ex => ex.nonce !== nonce)) {
logger.warn('Nonce is different, should not reach this point')
}
const exchanges = await getExchangeMessages(startBlock, endBlock)
const exchangesData = exchanges.map(msg => JSON.parse(msg.content))
const tx = new Transaction({
from,
accountNumber: account.account_number,
sequence: nonce,
recipients: exchangesData.map(({ value, recipient }) => ({ to: recipient, tokens: value })),
asset: FOREIGN_ASSET,
memo: `Attempt ${attempt}`
})
if (exchanges.length > 0 && account.sequence <= nonce) {
const recipients = exchangesData.map(({ value, recipient }) => ({ to: recipient, tokens: value }))
const hash = sha256(tx.getSignBytes())
logger.info(`Starting signature generation for transaction hash ${hash}`)
const done = await sign(keysFile, hash, tx, publicKey) && await waitForAccountNonce(from, nonce + 1)
while (true) {
logger.info(`Building corresponding transfer transaction, nonce ${nonce}`)
if (done) {
exchanges.forEach(msg => channel.ack(msg))
break
const tx = new Transaction({
from,
accountNumber: account.account_number,
sequence: nonce,
recipients,
asset: FOREIGN_ASSET,
memo: `Attempt ${attempt}`
})
const hash = sha256(tx.getSignBytes())
logger.info(`Starting signature generation for transaction hash ${hash}`)
const done = await sign(keysFile, hash, tx, publicKey) && await waitForAccountNonce(from, nonce + 1)
if (done) {
exchanges.forEach(msg => channel.ack(msg))
break
}
attempt = nextAttempt ? nextAttempt : attempt + 1
logger.warn(`Sign failed, starting next attempt ${attempt}`)
nextAttempt = null
await new Promise(resolve => setTimeout(resolve, 1000))
}
attempt = nextAttempt ? nextAttempt : attempt + 1
logger.warn(`Sign failed, starting next attempt ${attempt}`)
nextAttempt = null
await new Promise(resolve => setTimeout(resolve, 1000))
}
} else if (account.sequence <= nonce) {
const newKeysFile = `/keys/keys${newEpoch}.store`
@ -99,11 +107,11 @@ async function main () {
from,
accountNumber: account.account_number,
sequence: nonce,
recipients: [{
recipients: [ {
to,
tokens: account.balances.find(x => x.symbol === FOREIGN_ASSET).free,
bnbs: new BN(account.balances.find(x => x.symbol === 'BNB').free).minus(new BN(60000).div(10 ** 8)),
}],
} ],
asset: FOREIGN_ASSET,
memo: `Attempt ${attempt}`
})
@ -131,22 +139,22 @@ async function main () {
main()
async function getExchangeMessages(startBlock, endBlock) {
async function getExchangeMessages () {
logger.debug('Getting exchange messages')
const messages = []
do {
const msg = await exchangeQueue.get()
if (msg === false) {
break;
logger.warn('Reached the end of exchange queue, should not reach this point')
break
}
const data = JSON.parse(msg.content)
logger.debug('Got message %o', data)
if (data.blockNumber > endBlock) {
if (data.stub) {
channel.ack(msg)
break;
break
}
if (data.blockNumber >= startBlock)
messages.push(msg)
messages.push(msg)
} while (true)
logger.debug('Found %d messages', messages.length)
return messages