Skip to content

Commit

Permalink
Add peripherals utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
elmato committed Jun 26, 2023
1 parent edba11b commit fa06e46
Show file tree
Hide file tree
Showing 13 changed files with 1,318 additions and 0 deletions.
22 changes: 22 additions & 0 deletions peripherals/health_helper/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## Health check helper

This tiny script will keep getting last block from the node and compare the timestamp with current time. If the time difference is larger than certain threshold, the node is considered stale.

The scipt will response to http GET calls and return 200 if the node is healthy and 500 if the node is stale.


### To run

The script is simple enough so no npm install is necessary.
```
RPC_ENDPOINT=http://xx.xx.xx.xx:xx node index.js
```

### Environment variables
RPC_ENDPOINT: Endpoint of the node. No default value. Required.

LISTEN_PORT: Port to listen and report state. Default to 8080.

CHECK_INTERVAL: How often should the helper query last block (in ms). Default to 5000.

STALE_THRESHOLD: The time difference threshold for a node to be considered stale (in second). Default to 60.
68 changes: 68 additions & 0 deletions peripherals/health_helper/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
var http = require('http');

const url = process.env.RPC_ENDPOINT || 'http://localhost:80'
const listen_port = process.env.LISTEN_PORT || 8000
const check_interval = process.env.CHECK_INTERVAL || 5000
const stale_threshold = process.env.STALE_THRESHOLD || 60

var last_block = 0;
var stale = 1;

function intervalFunc() {
let post_data = '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest", false],"id":1}'
const options = {
hostname: url.hostname,
port: url.port,
path: '/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
}

let post_req = http
.request(options, response => {
var data = "";

response.on('data', function (chunk) {
data += chunk;
});

response.on('end', function () {
try {
const obj = JSON.parse(data);

last_block = obj.result.timestamp
let timestamp = Number(last_block)
let now = Math.floor(Date.now() / 1000)
if (now - timestamp > stale_threshold) {
stale = 1;
}
else {
stale = 0
}

}
catch (_) {
stale = 1;
}
})
})
.on("error", err => {
console.log("Error: " + err.message);
stale = 1;
});

post_req.write(post_data);
post_req.end();
}

setInterval(intervalFunc, check_interval);

http.createServer(function (req, res) {
res.writeHead(stale > 0 ? 500 : 200, { 'Content-Type': 'text/html' });
res.write(last_block.toString());
res.end();
}).listen(listen_port);

11 changes: 11 additions & 0 deletions peripherals/proxy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM openresty/openresty:alpine
ARG WRITE_ENDPOINT
ARG READ_ENDPOINT
ARG TEST_ENDPOINT
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
RUN sed -i "s/WRITE_ENDPOINT/${WRITE_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
RUN sed -i "s/READ_ENDPOINT/${READ_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
RUN sed -i "s/TEST_ENDPOINT/${TEST_ENDPOINT}/g" /usr/local/openresty/nginx/conf/nginx.conf
COPY eth-jsonrpc-access.lua /usr/local/openresty/nginx/eth-jsonrpc-access.lua
EXPOSE 80 443

26 changes: 26 additions & 0 deletions peripherals/proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# evm_proxy_nginx

Sample config for location:
```
location / {
set $jsonrpc_write_calls 'eth_sendRawTransaction,eth_gasPrice';
set $jsonrpc_read_calls 'xxx,xxx';
set $jsonrpc_test_calls 'xxx';
access_by_lua_file 'eth-jsonrpc-access.lua';
proxy_pass http://$proxy;
}
```

To build (You can change the endpoints through build-arg):
```
sudo docker build -t evm/tx_proxy --build-arg WRITE_ENDPOINT=host.docker.internal:18888 --build-arg READ_ENDPOINT=host.docker.internal:8881 --build-arg TEST_ENDPOINT=host.docker.internal:8882 .
```

To run:
```
mkdir -p logs
sudo docker run --add-host=host.docker.internal:host-gateway -p 80:80 -v ${PWD}/logs:/var/log/nginx -d --restart=always --name=tx_proxy evm/tx_proxy
```

109 changes: 109 additions & 0 deletions peripherals/proxy/eth-jsonrpc-access.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
local cjson = require('cjson')

local function empty(s)
return s == nil or s == ''
end

local function split(s)
local res = {}
local i = 1
for v in string.gmatch(s, "([^,]+)") do
res[i] = v
i = i + 1
end
return res
end

local function contains(arr, val)
for i, v in ipairs (arr) do
if v == val then
return true
end
end
return false
end

-- parse conf
local test_calls = nil
if not empty(ngx.var.jsonrpc_test_calls) then
test_calls = split(ngx.var.jsonrpc_test_calls)
end

-- parse conf
local write_calls = nil
if not empty(ngx.var.jsonrpc_write_calls) then
write_calls = split(ngx.var.jsonrpc_write_calls)
end

-- parse conf
local read_calls = nil
if not empty(ngx.var.jsonrpc_read_calls) then
read_calls = split(ngx.var.jsonrpc_read_calls)
end

-- get request content
ngx.req.read_body()

local body_data = ngx.req.get_body_data();
if empty(body_data) then
local file, err = io.open(ngx.req.get_body_file(), 'r')
if not file then
ngx.log(ngx.ERR, 'Unable to read body data')
ngx.exit(ngx.HTTP_BAD_REQUEST)
return
end
body_data = file:read()
io.close(file)
end

-- try to parse the body as JSON
local success, body = pcall(cjson.decode, body_data);
if not success then
ngx.log(ngx.ERR, 'invalid JSON request')
ngx.exit(ngx.HTTP_BAD_REQUEST)
return
end

local method = body['method']
local version = body['jsonrpc']

-- check we have a method and a version
if empty(method) or empty(version) then
ngx.log(ngx.ERR, 'no method and/or jsonrpc attribute')
ngx.exit(ngx.HTTP_BAD_REQUEST)
return
end

-- check the version is supported
if version ~= "2.0" then
ngx.log(ngx.ERR, 'jsonrpc version not supported: ' .. version)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
return
end

-- Proxy calls to "read"
if read_calls ~= nil then
if contains(read_calls, method) then
ngx.var.proxy = 'read'
return
end
end

-- Proxy calls to "write"
if write_calls ~= nil then
if contains(write_calls, method) then
ngx.var.proxy = 'write'
return
end
end

-- Proxy calls to "test"
if test_calls ~= nil then
if contains(test_calls, method) then
ngx.var.proxy = 'test'
return
end
end

ngx.exit(ngx.HTTP_FORBIDDEN)
return
92 changes: 92 additions & 0 deletions peripherals/proxy/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
worker_processes 5;
#daemon off;
error_log /var/log/nginx/error.log;
pid /var/log/nginx/nginx.pid;
worker_rlimit_nofile 8192;
user root root;
events {
worker_connections 4096;
}

http {
include /usr/local/openresty/nginx/conf/mime.types;
index index.html index.htm index.php;

upstream write {
server WRITE_ENDPOINT;
}

upstream read {
server READ_ENDPOINT;
keepalive 1000;
}

upstream test {
server TEST_ENDPOINT;
keepalive 1000;
}

default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
log_format postdata '$remote_addr [$time_local] $upstream_status $remote_addr $request_body';
sendfile on;
tcp_nopush on;

map $upstream_status $log_postdata {
default 0;
~^5 1;
}

server {
listen 80;
server_name localhost;

location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' '*';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Content-Type' 'text/html';
return 200 '<!DOCTYPE html>This is an API endpoint that only accepts JSON-RPC requests. <br> Please visit <a href = "https://docs.eosnetwork.com/docs/latest/eos-evm/">https://docs.eosnetwork.com/docs/latest/eos-evm/</a> for information about EOS EVM. \n';
}

resolver 127.0.0.11;
set $proxy "read";
set $jsonrpc_write_calls 'eth_sendRawTransaction,eth_gasPrice';
set $jsonrpc_read_calls 'net_version,eth_blockNumber,eth_chainId,eth_protocolVersion,eth_getBlockByHash,eth_getBlockByNumber,eth_getBlockTransactionCountByHash,eth_getBlockTransactionCountByNumber,eth_getUncleByBlockHashAndIndex,eth_getUncleByBlockNumberAndIndex,eth_getUncleCountByBlockHash,eth_getUncleCountByBlockNumber,eth_getTransactionByHash,eth_getRawTransactionByHash,eth_getTransactionByBlockHashAndIndex,eth_getRawTransactionByBlockHashAndIndex,eth_getTransactionByBlockNumberAndIndex,eth_getRawTransactionByBlockNumberAndIndex,eth_getTransactionReceipt,eth_getBlockReceipts,eth_estimateGas,eth_getBalance,eth_getCode,eth_getTransactionCount,eth_getStorageAt,eth_call,eth_callBundle,eth_createAccessList';
set $jsonrpc_test_calls 'eth_getLogs,debug_traceBlockByHash,debug_traceBlockByNumber,debug_traceTransaction,debug_traceCall,debug_traceCallMany,trace_call,trace_callMany,trace_rawTransaction,trace_replayBlockTransactions,trace_replayTransaction,trace_block,trace_filter,trace_get,trace_transaction';
access_by_lua_file 'eth-jsonrpc-access.lua';
proxy_pass http://$proxy;
proxy_set_header content-type "application/json";
proxy_set_header accept "application/json";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
access_log /var/log/nginx/error/${proxy}-post-data.log postdata if=$log_postdata;
}
}

}
Loading

0 comments on commit fa06e46

Please sign in to comment.