Commit 4d5b0407 authored by vicotor's avatar vicotor

add detail request log

parent 8d7de62c
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"github.com/ethereum/go-ethereum/common/lru"
"io" "io"
"log" "log"
"net" "net"
...@@ -68,6 +69,11 @@ type RPCResponse struct { ...@@ -68,6 +69,11 @@ type RPCResponse struct {
Error interface{} `json:"error,omitempty"` Error interface{} `json:"error,omitempty"`
} }
type TxArgs struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
}
var ( var (
db *sql.DB db *sql.DB
rpcBackend = os.Getenv("ETH_RPC_BACKEND") // Real Ethereum RPC address, recommend using environment variable rpcBackend = os.Getenv("ETH_RPC_BACKEND") // Real Ethereum RPC address, recommend using environment variable
...@@ -106,6 +112,9 @@ var ( ...@@ -106,6 +112,9 @@ var (
localBlacklistFile string localBlacklistFile string
localBlacklist map[string]struct{} localBlacklist map[string]struct{}
localBlacklistMu sync.RWMutex localBlacklistMu sync.RWMutex
// tx cache lru
txCache = lru.NewCache[string, TxArgs](10000)
) )
type visitor struct { type visitor struct {
...@@ -271,17 +280,17 @@ func main() { ...@@ -271,17 +280,17 @@ func main() {
func isSendTxFromBlacklist(req RPCRequest, ip string) bool { func isSendTxFromBlacklist(req RPCRequest, ip string) bool {
if req.Method == "eth_sendRawTransaction" && len(req.Params) > 0 { if req.Method == "eth_sendRawTransaction" && len(req.Params) > 0 {
if rawHex, ok := req.Params[0].(string); ok { if rawHex, ok := req.Params[0].(string); ok {
if fromAddr, err := getSenderFromRawTx(rawHex); err == nil { if txArgs, ok := getEthTx(rawHex); ok {
// Check local blacklist first // Check local blacklist first
if isLocalBlacklisted(fromAddr) { if isLocalBlacklisted(txArgs.From) {
log.Printf("sender %s is in local blacklist, banning IP %s\n", fromAddr, ip) log.Printf("sender %s is in local blacklist, banning IP %s\n", txArgs.From, ip)
return true return true
} else { } else {
// check in contract blacklist. // check in contract blacklist.
if ethClient != nil && blacklistContract != (common.Address{}) { if ethClient != nil && blacklistContract != (common.Address{}) {
inBlack, _ := CachedIsInBlacklist(ethClient, blacklistContract, common.HexToAddress(strings.ToLower(fromAddr))) inBlack, _ := CachedIsInBlacklist(ethClient, blacklistContract, common.HexToAddress(strings.ToLower(txArgs.From)))
if inBlack { if inBlack {
log.Printf("sender %s is in contract blacklist, banning IP %s\n", fromAddr, ip) log.Printf("sender %s is in contract blacklist, banning IP %s\n", txArgs.From, ip)
return inBlack return inBlack
} }
} }
...@@ -307,6 +316,36 @@ func isFromInBlacklist(addr string) bool { ...@@ -307,6 +316,36 @@ func isFromInBlacklist(addr string) bool {
return false return false
} }
func dumpRequestInfo(req RPCRequest, ip string) {
switch req.Method {
case "eth_sendTransaction":
// get rawtx and unmarshal to get from and to.
if rawHex, ok := req.Params[0].(string); ok {
if txArgs, ok := getEthTx(rawHex); ok {
log.Printf("detail request %s from ip %s, from: %s, to: %s\n", req.Method, ip, txArgs.From, txArgs.To)
}
}
case "eth_call", "eth_estimateGas":
param := req.Params[0]
// how to parse the json struct to go struct CallArgs
if argMap, ok := param.(map[string]interface{}); ok {
from, _ := argMap["from"].(string)
to, _ := argMap["to"].(string)
if from != "" && to != "" {
log.Printf("detail request %s from ip %s, from: %s, to: %s\n", req.Method, ip, from, to)
}
}
case "eth_getBalance", "eth_getTransactionCount":
from, ok := req.Params[0].(string)
if ok {
log.Printf("detail request %s from ip %s, from: %s\n", req.Method, ip, from)
}
default:
}
}
func proxyHandler(w http.ResponseWriter, r *http.Request) { func proxyHandler(w http.ResponseWriter, r *http.Request) {
// Add CORS support // Add CORS support
setCORSHeaders(w, r) setCORSHeaders(w, r)
...@@ -398,6 +437,8 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { ...@@ -398,6 +437,8 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
// dump ip, method, from, to info.
dumpRequestInfo(req, ip)
} }
forwardToBackend(w, body) forwardToBackend(w, body)
} }
...@@ -474,21 +515,25 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { ...@@ -474,21 +515,25 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
dumpRequestInfo(req, ip)
// Forward other cases directly // Forward other cases directly
forwardToBackend(w, body) forwardToBackend(w, body)
} }
// getSenderFromRawTx decodes a raw transaction hex (0x...) and returns the sender address as a hex string. func getEthTx(rawHex string) (TxArgs, bool) {
func getSenderFromRawTx(rawHex string) (string, error) { if v, exist := txCache.Get(rawHex); exist {
return v, true
}
arg := TxArgs{}
// strip 0x if present // strip 0x if present
b, err := hexutil.Decode(rawHex) b, err := hexutil.Decode(rawHex)
if err != nil { if err != nil {
return "", err return arg, false
} }
var tx types.Transaction var tx types.Transaction
if err := tx.UnmarshalBinary(b); err != nil { if err := tx.UnmarshalBinary(b); err != nil {
return "", err return arg, false
} }
// determine signer // determine signer
var signer types.Signer var signer types.Signer
...@@ -499,9 +544,23 @@ func getSenderFromRawTx(rawHex string) (string, error) { ...@@ -499,9 +544,23 @@ func getSenderFromRawTx(rawHex string) (string, error) {
} }
from, err := types.Sender(signer, &tx) from, err := types.Sender(signer, &tx)
if err != nil { if err != nil {
return "", err return arg, false
}
arg.From = strings.ToLower(from.Hex())
if tx.To() != nil {
arg.To = strings.ToLower(tx.To().Hex())
}
txCache.Add(rawHex, arg)
return arg, true
}
// getSenderFromRawTx decodes a raw transaction hex (0x...) and returns the sender address as a hex string.
func getSenderFromRawTx(rawHex string) (string, error) {
txArgs, ok := getEthTx(rawHex)
if !ok {
return "", fmt.Errorf("failed to decode raw transaction")
} }
return strings.ToLower(from.Hex()), nil return txArgs.From, nil
} }
func setCORSHeaders(w http.ResponseWriter, r *http.Request) { func setCORSHeaders(w http.ResponseWriter, r *http.Request) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment