Skip to content

Commit 442c09f

Browse files
committed
Merge branch 'main' into kayan_ws_fork_test
2 parents a6f8b8e + e0698c5 commit 442c09f

File tree

17 files changed

+473
-130
lines changed

17 files changed

+473
-130
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ project(eos-evm-node)
2020

2121
set(VERSION_MAJOR 0)
2222
set(VERSION_MINOR 6)
23-
set(VERSION_PATCH 0)
23+
set(VERSION_PATCH 1)
2424
#set(VERSION_SUFFIX stable)
2525

2626
if(VERSION_SUFFIX)

external/silkworm

peripherals/eos-evm-ws-proxy/block-monitor.js

Lines changed: 92 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,94 +2,165 @@ const EventEmitter = require('events');
22
const axios = require('axios');
33
const {Web3} = require('web3');
44
const Deque = require('collections/deque');
5-
const {num_from_id} = require('./utils');
5+
const {num_from_id, convert_to_epoch} = require('./utils');
6+
const { clearTimeout } = require('timers');
67
class BlockMonitor extends EventEmitter {
78

8-
constructor({ web3_rpc_endpoint, nodeos_rpc_endpoint, poll_interval, logger}) {
9+
constructor({ web3_rpc_endpoint, nodeos_rpc_endpoint, poll_interval, genesis, logger}) {
910
super();
1011
this.web3_rpc_endpoint = web3_rpc_endpoint;
1112
this.nodeos_rpc_endpoint = nodeos_rpc_endpoint;
1213
this.poll_interval = poll_interval;
1314
this.web3 = new Web3(web3_rpc_endpoint);
1415
this.logger = logger;
16+
this.genesis = genesis;
17+
18+
if(this.genesis == undefined || this.genesis.timestamp == undefined) throw ("invalid genesis timestamp");
19+
this.genesis_timestamp = parseInt(this.genesis.timestamp, 16);
20+
this.logger.debug(`Using genesis timestamp: ${this.genesis_timestamp}`);
1521

1622
this.reversible_blocks = new Deque();
1723
this.run = false;
1824
this.timer_id = null;
1925
}
2026

21-
async get_eos_lib() {
22-
const response = await axios.post(this.nodeos_rpc_endpoint+'/v1/chain/get_info', {});
23-
return response.data.last_irreversible_block_num;
27+
async get_evm_lib() {
28+
let response = await axios.post(this.nodeos_rpc_endpoint+'/v1/chain/get_info', {});
29+
response = await axios.post(this.nodeos_rpc_endpoint+'/v1/chain/get_block', {block_num_or_id:response.data.last_irreversible_block_num});
30+
let lib = this.timestamp_to_evm_block_num(convert_to_epoch(response.data.timestamp));
31+
this.logger.debug(`BlockMonitor::get_evm_lib ${lib}`);
32+
return lib;
2433
}
2534

35+
timestamp_to_evm_block_num(timestamp) {
36+
const block_interval = 1;
37+
if (timestamp < this.genesis_timestamp) {
38+
return 0;
39+
}
40+
return 1 + Math.floor((timestamp - this.genesis_timestamp) / block_interval);
41+
}
42+
43+
2644
remove_front_block() {
2745
const block = this.reversible_blocks.shift();
46+
this.logger.debug(`BlockMonitor::remove_front_block ${block.number}`);
2847
this.emit('block_removed', {block});
2948
}
3049

3150
fork_last_block() {
3251
const block = this.reversible_blocks.pop();
33-
this.logger.debug(`FORK_LAST_BLOCK ${block}`);
52+
this.logger.debug(`BlockMonitor::fork_last_block ${block.number}`);
3453
this.emit('block_forked', {block});
3554
return this.reversible_blocks.peekBack();
3655
}
3756

3857
append_new_block(block) {
3958
this.reversible_blocks.add(block);
59+
this.logger.debug(`BlockMonitor::append_new_block ${block.number} ${block.hash}`);
4060
this.emit('block_appended', {block});
61+
return block;
62+
}
63+
64+
async getBlockWithLogs(number_) {
65+
let number = Number(number_);
66+
67+
let id1 = "get_block_" + number;
68+
let id2 = "get_logs_" + number;
69+
let requests = [
70+
{jsonrpc:"2.0",method:"eth_getBlockByNumber",params:["0x" + number.toString(16), true], id: id1},
71+
{jsonrpc:"2.0",method:"eth_getLogs",params:[{fromBlock: "0x" + number.toString(16), toBlock: "0x" + number.toString(16)}], id: id2}
72+
]
73+
const results = await axios.post(this.web3_rpc_endpoint, requests);
74+
75+
if (!Array.isArray(results.data) || results.data.length != 2) {
76+
throw new Error("invalid RPC response of [getBlock, GetPastLogs] batch request");
77+
}
78+
const block = results.data[0].result;
79+
const logs = results.data[1].result;
80+
81+
block.logs = logs;
82+
//console.log("RPC batch result:" + JSON.stringify(block));
83+
return block;
84+
}
85+
86+
async get_next_block(block) {
87+
// need to be conservative, sometimes getLogs return empty result for head block
88+
let head_block = await this.web3.eth.getBlock("latest", true);
89+
if( head_block == null ) return null;
90+
91+
if(block == null)
92+
return await this.getBlockWithLogs(Number(head_block.number) - 1);
93+
94+
let next_block_num = Number(block.number) + 1;
95+
96+
let max_block_num = Number(head_block.number) - 1;
97+
if (next_block_num >= max_block_num) {
98+
return null;
99+
}
100+
101+
return await this.getBlockWithLogs(next_block_num);
41102
}
42103

43104
async poll() {
44105
try {
106+
45107
let last = this.reversible_blocks.peekBack();
46108
if( last == undefined ) {
47-
last = await this.web3.eth.getBlock("latest", true);
48-
this.append_new_block(last);
109+
this.logger.debug("BlockMonitor::poll last not defined");
110+
last = await this.get_next_block()
111+
if (last != null) {
112+
this.logger.debug(`BlockMonitor::poll Obtained ${last.number}`);
113+
this.append_new_block(last);
114+
} else {
115+
throw new Error("BlockMonitor::poll Unable to get block");
116+
}
49117
}
50118

51-
let next_block = await this.web3.eth.getBlock(last.number+BigInt(1), true);
119+
let next_block = await this.get_next_block(last);
52120
let found_next_block = false;
53121
while(last != null && next_block != null) {
54122
found_next_block = true;
55123
if(next_block.parentHash == last.hash) {
56-
this.append_new_block(next_block);
57-
last = next_block;
58-
next_block = await this.web3.eth.getBlock(last.number+BigInt(1), true);
124+
last = this.append_new_block(next_block);
125+
next_block = await this.get_next_block(last);
59126
} else {
127+
this.logger.debug(`BlockMonitor::poll next: ${next_block.number} ${next_block.parentHash} != last: ${last.number} ${last.hash}`);
60128
last = this.fork_last_block();
129+
next_block = await this.get_next_block(last);
61130
}
62131
}
63132

64133
if( found_next_block == true ) {
65-
const eos_lib = await this.get_eos_lib();
66-
while(this.reversible_blocks.length > 0 && num_from_id(this.reversible_blocks.peek().mixHash) <= eos_lib) {
67-
this.logger.debug(`eoslib: ${eos_lib} ${num_from_id(this.reversible_blocks.peek().mixHash)} ${this.reversible_blocks.peek().number} ${this.reversible_blocks.peek().mixHash}`);
134+
const evm_lib = await this.get_evm_lib();
135+
while(this.reversible_blocks.length > 0 && this.reversible_blocks.peek().number < evm_lib) {
68136
this.remove_front_block();
69137
}
70138
}
71139

72140
} catch (error) {
73-
this.logger.error(error.message);
141+
this.logger.error(`BlockMonitor::poll => ERR: ${error.message}`);
74142
}
75143

76144
if(this.run == true) {
145+
if (this.timer_id != null) clearTimeout(this.timer_id);
77146
this.timer_id = setTimeout(() => this.poll(), this.poll_interval || 5000);
78147
} else {
79148
this.reversible_blocks.clear();
80-
this.logger.info("BlockMonitor stopped");
149+
this.logger.info("BlockMonitor::poll => Stopped");
150+
if (this.timer_id != null) clearTimeout(this.timer_id);
81151
}
82152
}
83153

84154
start() {
85-
this.logger.info("BlockMonitor start");
155+
if( this.run == true ) return;
156+
this.logger.info("BlockMonitor::start => BlockMonitor starting");
86157
this.run = true;
87-
setTimeout(() => this.poll(), 0);
158+
if (this.timer_id != null) clearTimeout(this.timer_id);
159+
this.timer_id = setTimeout(() => this.poll(), 0);
88160
}
89161

90162
stop() {
91-
clearTimeout(this.timer_id);
92-
this.logger.info("BlockMonitor stopping");
163+
this.logger.info("BlockMonitor::stop => BlockMonitor stopping");
93164
this.run = false;
94165
}
95166

peripherals/eos-evm-ws-proxy/config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const poll_interval = parseInt(process.env.POLL_INTERVAL, 10) || 1000;
77
const max_logs_subs_per_connection = parseInt(process.env.MAX_LOGS_SUBS_PER_CONNECTION, 10) || 1;
88
const max_minedtx_subs_per_connection = parseInt(process.env.MAX_MINEDTX_SUBS_PER_CONNECTION, 10) || 1;
99
const log_level = process.env.LOG_LEVEL || 'info';
10+
const genesis_json = process.env.GENESIS_JSON || 'eos-evm-genesis.json';
1011

1112
module.exports = {
1213
ws_listening_port,
@@ -16,5 +17,6 @@ module.exports = {
1617
poll_interval,
1718
max_logs_subs_per_connection,
1819
max_minedtx_subs_per_connection,
19-
log_level
20+
log_level,
21+
genesis_json
2022
};
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
const config = require('./config');
22
const {logger} = require('./logger');
33
const SubscriptionServer = require('./subscription-server');
4-
const server = new SubscriptionServer({...config, logger});
5-
server.start();
4+
5+
try {
6+
const server = new SubscriptionServer({...config, logger});
7+
server.start();
8+
} catch (error) {
9+
logger.error(`main: ${error.message}`);
10+
}

peripherals/eos-evm-ws-proxy/subscription-server.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ const EventEmitter = require('events');
22
const WebSocketHandler = require('./websocket-handler');
33
const BlockMonitor = require('./block-monitor');
44
const {Web3} = require('web3');
5-
const {bigint_replacer} = require('./utils');
6-
5+
const {bigint_replacer, load_json_file} = require('./utils');
76
class SubscriptionServer extends EventEmitter {
87

9-
constructor({web3_rpc_endpoint, nodeos_rpc_endpoint, ws_listening_host, ws_listening_port, poll_interval, max_logs_subs_per_connection, max_minedtx_subs_per_connection, logger}) {
8+
constructor({web3_rpc_endpoint, nodeos_rpc_endpoint, ws_listening_host, ws_listening_port, poll_interval, max_logs_subs_per_connection, max_minedtx_subs_per_connection, genesis_json, logger}) {
109
super();
1110

12-
this.block_monitor = new BlockMonitor({web3_rpc_endpoint, nodeos_rpc_endpoint, poll_interval, logger});
11+
const genesis = load_json_file(genesis_json);
12+
13+
this.block_monitor = new BlockMonitor({web3_rpc_endpoint, nodeos_rpc_endpoint, poll_interval, genesis, logger});
1314
this.web_socket_handler = new WebSocketHandler({ws_listening_host, ws_listening_port, web3_rpc_endpoint, logger});
1415
this.max_logs_subs_per_connection = max_logs_subs_per_connection;
1516
this.max_minedtx_subs_per_connection = max_minedtx_subs_per_connection;
1617
this.web3 = new Web3(web3_rpc_endpoint);
1718
this.logger = logger
19+
this.genesis = genesis;
1820

1921
this.new_head_subs = new Map();
2022
this.logs_subs = new Map();
@@ -55,21 +57,21 @@ class SubscriptionServer extends EventEmitter {
5557
}
5658

5759
handle_block_removed({block}) {
58-
this.logger.debug(`handle_block_removed: ${block.number}`);
60+
this.logger.debug(`SubscriptionServer::handle_block_removed: ${block.number}`);
5961
if(this.logs_sent.has(block.number)) {
6062
this.logs_sent.delete(block.number);
6163
}
6264
}
6365

6466
async handle_block_forked({block}) {
65-
this.logger.debug(`handle_block_forked: ${block.number}`);
67+
this.logger.debug(`SubscriptionServer::handle_block_forked: ${block.number}`);
6668
const events_sent_at_block = this.logs_sent.get(block.number);
6769
if (events_sent_at_block != undefined) {
6870
for(const event_sent of events_sent_at_block) {
6971
event_sent.msg.params.result.removed = true;
7072
event_sent.client.ws.send(JSON.stringify(event_sent.msg, bigint_replacer));
7173
}
72-
this.logger.debug(`REMOVING ${block.number}`);
74+
this.logger.debug(`SubscriptionServer::handle_block_forked: REMOVING ${block.number}`);
7375
this.logs_sent.delete(block.number);
7476
}
7577
await this.process_mined_transactions_subscriptions(block, true);
@@ -144,9 +146,8 @@ class SubscriptionServer extends EventEmitter {
144146
// Process all `logs` subscriptions
145147
// Get logs from the recently appended block
146148
if(this.logs_subs.size > 0) {
147-
const logs = await this.web3.eth.getPastLogs({fromBlock:block.number, toBlock:block.number});
148-
this.logger.debug("LOG => ", JSON.stringify(logs, bigint_replacer));
149-
for(const log of logs) {
149+
this.logger.debug("LOG => ", JSON.stringify(block.logs, bigint_replacer));
150+
for(const log of block.logs) {
150151
for(const [subid, client] of this.logs_subs) {
151152
if(this.logs_filter_match(client.filter, log)) {
152153
this.send_logs_response_and_save(block, client, subid, log);
@@ -194,7 +195,7 @@ class SubscriptionServer extends EventEmitter {
194195
for (const [_, client] of this.new_head_subs) {
195196
if(ws === client.ws) { throw new Error('Already subscribed');}
196197
}
197-
this.logger.debug(`Adding newHeads subscription ${subid}`);
198+
this.logger.debug(`SubscriptionServer::handle_new_heads: Adding newHeads subscription ${subid}`);
198199
this.new_head_subs.set(subid, {ws});
199200
this.check_start_monitor();
200201
}
@@ -207,7 +208,7 @@ class SubscriptionServer extends EventEmitter {
207208
if( total_logs_subs >= this.max_logs_subs_per_connection ) {
208209
throw new Error('Max logs subscriptions reached');
209210
}
210-
this.logger.debug(`Adding logs subscription ${subid}`);
211+
this.logger.debug(`SubscriptionServer::handle_logs: Adding logs subscription ${subid}`);
211212
this.logs_subs.set(subid, {ws, filter});
212213
this.check_start_monitor();
213214
}
@@ -220,7 +221,7 @@ class SubscriptionServer extends EventEmitter {
220221
if( total_minedtx_subs >= this.max_minedtx_subs_per_connection ) {
221222
throw new Error("Max minedTransactions subscriptions reached");
222223
}
223-
this.logger.debug(`Adding minedTransactions subscription ${subid}`);
224+
this.logger.debug(`SubscriptionServer::handle_minedTransactions: Adding minedTransactions subscription ${subid}`);
224225
this.mined_transactions_subs.set(subid, {ws, filter});
225226
this.check_start_monitor();
226227
}
@@ -239,7 +240,7 @@ class SubscriptionServer extends EventEmitter {
239240
throw new Error('Not found');
240241
}
241242

242-
this.logger.debug(`Unsubscribing ${subid}`);
243+
this.logger.debug(`SubscriptionServer::handle_unsubscribe: Unsubscribing ${subid}`);
243244
subscription_map.delete(subid);
244245
this.check_stop_monitor();
245246
}
@@ -248,21 +249,21 @@ class SubscriptionServer extends EventEmitter {
248249

249250
for (const [subid, client] of this.new_head_subs) {
250251
if(ws === client.ws) {
251-
this.logger.debug(`Removing new_head_subs ${subid}`);
252+
this.logger.debug(`SubscriptionServer::handle_disconnect: Removing new_head_subs ${subid}`);
252253
this.new_head_subs.delete(subid);
253254
}
254255
}
255256

256257
for (const [subid, client] of this.logs_subs) {
257258
if(ws === client.ws) {
258-
this.logger.debug(`Removing logs_subs ${subid}`);
259+
this.logger.debug(`SubscriptionServer::handle_disconnect: Removing logs_subs ${subid}`);
259260
this.logs_subs.delete(subid);
260261
}
261262
}
262263

263264
for (const [subid, client] of this.mined_transactions_subs) {
264265
if(ws === client.ws) {
265-
this.logger.debug(`Removing mined_transactions_subs ${subid}`);
266+
this.logger.debug(`SubscriptionServer::handle_disconnect:Removing mined_transactions_subs ${subid}`);
266267
this.mined_transactions_subs.delete(subid);
267268
}
268269
}

peripherals/eos-evm-ws-proxy/utils.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
const fs = require('fs');
2+
13
function is_plain_object(value) {
24
return Object.prototype.toString.call(value) === '[object Object]';
35
}
46

7+
function load_json_file(path) {
8+
try {
9+
const data = fs.readFileSync(path, 'utf8');
10+
return JSON.parse(data);
11+
} catch (error) {
12+
throw error;
13+
}
14+
}
15+
516
function num_from_id(id) {
617
if( id.startsWith('0x') ) {
718
id = id.substring(2);
@@ -16,9 +27,15 @@ function bigint_replacer(key, value) {
1627
return value;
1728
}
1829

30+
function convert_to_epoch(dateString) {
31+
return Math.floor(new Date(dateString+"+0000").getTime() / 1000);
32+
}
33+
1934
module.exports = {
2035
is_plain_object,
2136
num_from_id,
22-
bigint_replacer
37+
bigint_replacer,
38+
convert_to_epoch,
39+
load_json_file
2340
};
24-
41+

peripherals/proxy/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
66
RUN sed -i "s/WRITE_ENDPOINT/${WRITE_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
77
RUN sed -i "s/READ_ENDPOINT/${READ_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
88
RUN sed -i "s/TEST_ENDPOINT/${TEST_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
9+
RUN sed -i "s/WS_ENDPOINT/${WS_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
910
COPY eth-jsonrpc-access.lua /usr/local/openresty/nginx/eth-jsonrpc-access.lua
1011
EXPOSE 80 443
1112

0 commit comments

Comments
 (0)