Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

several fixes to increase reliability on staging #594

Merged
merged 13 commits into from
Mar 30, 2022
104 changes: 87 additions & 17 deletions cli/lib/nf3.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -509,11 +509,19 @@ class Nf3 {
*/
async getInstantWithdrawalRequestedEmitter() {
const emitter = new EventEmitter();
const connection = new WebSocket(this.optimistWsUrl);
let connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection); // save so we can close it properly later
const ping = async () => {
if (!connection) return;
if (connection.readyState !== WebSocket.OPEN) return;
if (!connection || connection.readyState !== WebSocket.OPEN) {
// Attempt to fix https://github.com/EYBlockchain/nightfall_3/issues/569
try {
connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection);
} catch (e) {
logger.debug('Error opening socket ', e);
return;
}
}
connection.ping();
setTimeout(ping, 15000);
};
Expand Down Expand Up @@ -688,12 +696,20 @@ class Nf3 {
*/
async startProposer() {
const newGasBlockEmitter = new EventEmitter();
const connection = new WebSocket(this.optimistWsUrl);
let connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection); // save so we can close it properly later
// Ping function to keep WS open. Send beat every 15 seconds
const ping = async () => {
if (!connection) return;
if (connection.readyState !== WebSocket.OPEN) return;
if (!connection || connection.readyState !== WebSocket.OPEN) {
// Attempt to fix https://github.com/EYBlockchain/nightfall_3/issues/569
try {
connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection);
} catch (e) {
logger.debug('Error opening socket ', e);
return;
}
}
connection.ping();
setTimeout(ping, 15000);
};
Expand Down Expand Up @@ -754,11 +770,19 @@ class Nf3 {
*/
async getNewBlockEmitter() {
const newBlockEmitter = new EventEmitter();
const connection = new WebSocket(this.optimistWsUrl);
let connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection); // save so we can close it properly later
const ping = async () => {
if (!connection) return;
if (connection.readyState !== WebSocket.OPEN) return;
if (!connection || connection.readyState !== WebSocket.OPEN) {
// Attempt to fix https://github.com/EYBlockchain/nightfall_3/issues/569
try {
connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection);
} catch (e) {
logger.debug('Error opening socket ', e);
return;
}
}
connection.ping();
setTimeout(ping, 15000);
};
Expand Down Expand Up @@ -807,11 +831,19 @@ class Nf3 {
@async
*/
async startChallenger() {
const connection = new WebSocket(this.optimistWsUrl);
let connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection); // save so we can close it properly later
const ping = async () => {
if (!connection) return;
if (connection.readyState !== WebSocket.OPEN) return;
if (!connection || connection.readyState !== WebSocket.OPEN) {
// Attempt to fix https://github.com/EYBlockchain/nightfall_3/issues/569
try {
connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection);
} catch (e) {
logger.debug('Error opening socket ', e);
return;
}
}
connection.ping();
setTimeout(ping, 15000);
};
Expand Down Expand Up @@ -840,11 +872,19 @@ class Nf3 {
*/
async getChallengeEmitter() {
const newChallengeEmitter = new EventEmitter();
const connection = new WebSocket(this.optimistWsUrl);
let connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection); // save so we can close it properly later
const ping = async () => {
if (!connection) return;
if (connection.readyState !== WebSocket.OPEN) return;
if (!connection || connection.readyState !== WebSocket.OPEN) {
// Attempt to fix https://github.com/EYBlockchain/nightfall_3/issues/569
try {
connection = new WebSocket(this.optimistWsUrl);
this.websockets.push(connection);
} catch (e) {
logger.debug('Error opening socket ', e);
return;
}
}
connection.ping();
setTimeout(ping, 15000);
};
Expand Down Expand Up @@ -963,8 +1003,26 @@ class Nf3 {
Set a Web3 Provider URL
*/
async setWeb3Provider() {
this.web3 = new Web3(this.web3WsUrl);
this.web3.eth.transactionBlockTimeout = 200;
// initialization of web3 provider has been taken from common-files/utils/web3.mjs
// Target is to mainain web3 socker alive
const WEB3_PROVIDER_OPTIONS = {
clientConfig: {
// Useful to keep a connection alive
keepalive: true,
keepaliveInterval: 10,
},
timeout: 3600000,
reconnect: {
auto: true,
delay: 5000, // ms
maxAttempts: 120,
onTimeout: false,
},
};
const provider = new Web3.providers.WebsocketProvider(this.web3WsUrl, WEB3_PROVIDER_OPTIONS);

this.web3 = new Web3(provider);
this.web3.eth.transactionBlockTimeout = 2000;
this.web3.eth.transactionConfirmationBlocks = 12;
if (typeof window !== 'undefined') {
if (window.ethereum && this.ethereumSigningKey === '') {
Expand All @@ -975,6 +1033,18 @@ class Nf3 {
throw new Error('No Web3 provider found');
}
}

provider.on('error', err => logger.error(`web3 error: ${err}`));
provider.on('connect', () => logger.info('Blockchain Connected ...'));
provider.on('end', () => logger.info('Blockchain disconnected'));

const checkActive = () => {
if (!this.web3.currentProvider.connected) {
this.web3.setProvider(provider);
}
setTimeout(checkActive, 2000);
};
checkActive();
}

/**
Expand Down
5 changes: 2 additions & 3 deletions common-files/utils/mongo.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ export default {
// Check if we are connecting to MongoDb or DocumentDb
if (url.includes('amazonaws')) {
// retrieve user and password from secrets
const { MONGO_INITDB_ROOT_PASSWORD, MONGO_INITDB_ROOT_USERNAME, MONGO_CA } = process.env;
const { MONGO_INITDB_ROOT_PASSWORD, MONGO_INITDB_ROOT_USERNAME } = process.env;
const client = await new MongoClient(
`mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@${url}:27017/?tls=true&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false`,
`mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@${url}:27017/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false`,
{
tlsCAFile: `${MONGO_CA}`, // Specify the DocDB; cert
useUnifiedTopology: true,
},
);
Expand Down
18 changes: 17 additions & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ module.exports = {
clientConfig: {
// Useful to keep a connection alive
keepalive: true,
keepaliveInterval: 60000,
// Keep keepalive interval small so that socket doesn't die
keepaliveInterval: 1500,
},
timeout: 3600000,
reconnect: {
Expand Down Expand Up @@ -255,6 +256,21 @@ module.exports = {
address: '0xB5Acbe9a0F1F8B98F3fC04471F7fE5d2c222cB44',
amount: 200,
},
{
name: 'Test-Eth',
address: '0x3f152B63Ec5CA5831061B2DccFb29a874C317502',
amount: '10000000000000000000000',
},
{
name: 'MATIC',
address: '0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae',
amount: '10000000000000000000000',
},
{
name: 'USDC',
address: '0x07865c6e87b9f70255377e024ace6630c1eaa37f',
amount: '1000000000000',
},
],
},

Expand Down
6 changes: 6 additions & 0 deletions nightfall-deployer/migrations/3_test_tokens_migration.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {
restrictions: { erc20default },
addresses,
},
RESTRICTIONS,
} = config;
const { DEPLOY_MOCK_TOKENS = true } = process.env;

Expand All @@ -20,6 +21,11 @@ const nERC721 = 35;
module.exports = function (deployer, _, accounts) {
deployer.then(async () => {
const restrictions = await Shield.deployed();

for (let token of RESTRICTIONS.tokens) {
console.log(`Max deposit restriction for ${token.name}: ${token.amount}`);
await restrictions.setRestriction(token.address, token.amount);
}

if (DEPLOY_MOCK_TOKENS === 'false') return;
await deployer.deploy(ERC20Mock, 1001010000000000); // initialSupply
Expand Down
4 changes: 3 additions & 1 deletion nightfall-optimist/src/event-handlers/block-proposed.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import WebSocket from 'ws';
import logger from 'common-files/utils/logger.mjs';
import Timber from 'common-files/classes/timber.mjs';
import config from 'config';
Expand Down Expand Up @@ -30,7 +31,7 @@ async function blockProposedEventHandler(data) {
const { block, transactions } = await getProposeBlockCalldata(data);

// If a service is subscribed to this websocket and listening for events.
if (ws)
if (ws && ws.readyState === WebSocket.OPEN) {
await ws.send(
JSON.stringify({
type: 'blockProposed',
Expand All @@ -42,6 +43,7 @@ async function blockProposedEventHandler(data) {
},
}),
);
}
logger.info('Received BlockProposed event');
try {
// and save the block to facilitate later lookup of block data
Expand Down
7 changes: 6 additions & 1 deletion nightfall-optimist/src/services/block-assembler.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
This module does all of the heaving lifting for a Proposer: It assembles blocks
from posted transactions and proposes these blocks.
*/
import WebSocket from 'ws';
import config from 'config';
import logger from 'common-files/utils/logger.mjs';
import {
Expand Down Expand Up @@ -99,7 +100,7 @@ export async function conditionalMakeBlock(proposer) {
}
// TODO - check ws readyState is OPEN => CLOSED .WebSocket.OPEN(1), CONNECTING(0), CLOSING(2), CLOSED(3)
// before sending Poposed block. If not Open, try to open it
if (ws) {
if (ws && ws.readyState === WebSocket.OPEN) {
await ws.send(
JSON.stringify({
type: 'block',
Expand All @@ -109,6 +110,10 @@ export async function conditionalMakeBlock(proposer) {
}),
);
logger.debug('Send unsigned block-assembler transactions to ws client');
} else if (ws) {
logger.debug('Block not sent. Socket state', ws.readyState);
} else {
logger.debug('Block not sent. uinitialized socket');
}
// remove the transactions from the mempool so we don't keep making new
// blocks with them
Expand Down
6 changes: 4 additions & 2 deletions test/ping-pong/user-local/src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ async function localTest() {
const ercAddress = await nf3.getContractAddress(ERC20_NAME);
const startBalance = await retrieveL2Balance(nf3);

let offchainTx = !!IS_TEST_RUNNER;
// Create a block of deposits
for (let i = 0; i < txPerBlock; i++) {
await nf3.deposit(ercAddress, tokenType, value, tokenId);
Expand All @@ -43,7 +44,7 @@ async function localTest() {
for (let i = 0; i < TEST_LENGTH; i++) {
await waitForSufficientBalance(nf3, value);
try {
await nf3.transfer(false, ercAddress, tokenType, value, tokenId, recipients.user1);
await nf3.transfer(offchainTx, ercAddress, tokenType, value, tokenId, recipients.user1);
} catch (err) {
if (err.message.includes('No suitable commitments')) {
// if we get here, it's possible that a block we are waiting for has not been proposed yet
Expand All @@ -54,12 +55,13 @@ async function localTest() {
} seconds and try one last time`,
);
await new Promise(resolve => setTimeout(resolve, 10 * TX_WAIT));
await nf3.transfer(false, ercAddress, tokenType, value, tokenId, recipients.user1);
await nf3.transfer(offchainTx, ercAddress, tokenType, value, tokenId, recipients.user1);
}
}
await nf3.deposit(ercAddress, tokenType, value, tokenId);
await new Promise(resolve => setTimeout(resolve, TX_WAIT)); // this may need to be longer on a real blockchain
console.log(`Completed ${i + 1} pings`);
offchainTx = !offchainTx;
}

// Wait for sometime at the end to retrieve balance to include any transactions sent by the other use
Expand Down