-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
1,318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.