refactor(rpc): streamline RPC node selection and remove hardcoded defaults

This commit is contained in:
line-6000
2026-04-23 02:08:18 +08:00
parent 09514a6946
commit 91936d580f
13 changed files with 326 additions and 101 deletions
+4 -3
View File
@@ -18,8 +18,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
)
const bscDefaultWsURL = "wss://bsc.drpc.org"
type bscRecipientSnapshot struct {
addrs map[string]struct{}
}
@@ -68,7 +66,10 @@ func runBscListener(contracts []common.Address) {
}
}()
wsURL := resolveChainWsURL(mdb.NetworkBsc, bscDefaultWsURL)
wsURL, ok := resolveChainWsURL(mdb.NetworkBsc, "[BSC-WS]")
if !ok {
return
}
log.Sugar.Infof("[BSC-WS] connecting to %s watching %d contract(s)", wsURL, len(contracts))
query := ethereum.FilterQuery{
+15 -5
View File
@@ -90,12 +90,22 @@ func loadChainTokenContracts(network, logPrefix string) []common.Address {
}
// resolveChainWsURL picks a healthy WS endpoint from rpc_nodes for the
// given network, falling back to the provided default (usually the
// public node URL) when no row is configured.
func resolveChainWsURL(network, fallback string) string {
// given network. If no enabled node is configured, the caller skips the
// current listener run so admin-side disabled/deleted rows are respected.
func resolveChainWsURL(network, logPrefix string) (string, bool) {
node, err := data.SelectRpcNode(network, mdb.RpcNodeTypeWs)
if err == nil && node != nil && node.ID > 0 {
return node.Url
rpcURL := strings.TrimSpace(node.Url)
if rpcURL != "" {
return rpcURL, true
}
log.Sugar.Errorf("%s rpc_nodes id=%d has empty url", logPrefix, node.ID)
return "", false
}
return fallback
if err != nil {
log.Sugar.Errorf("%s resolve rpc_nodes err=%v", logPrefix, err)
} else {
log.Sugar.Warnf("%s no enabled %s WS RPC node configured in rpc_nodes", logPrefix, network)
}
return "", false
}
+67
View File
@@ -0,0 +1,67 @@
package task
import (
"testing"
"github.com/assimon/luuu/internal/testutil"
"github.com/assimon/luuu/model/dao"
"github.com/assimon/luuu/model/mdb"
)
func TestResolveChainWsURLRequiresEnabledRpcNode(t *testing.T) {
cleanup := testutil.SetupTestDatabases(t)
defer cleanup()
if got, ok := resolveChainWsURL(mdb.NetworkEthereum, "[TEST]"); ok {
t.Fatalf("resolveChainWsURL() = (%q, true), want false", got)
}
}
func TestResolveChainWsURLWithRow(t *testing.T) {
cleanup := testutil.SetupTestDatabases(t)
defer cleanup()
node := &mdb.RpcNode{
Network: mdb.NetworkEthereum,
Url: " wss://ethereum.example.com ",
Type: mdb.RpcNodeTypeWs,
Weight: 1,
Enabled: true,
Status: mdb.RpcNodeStatusOk,
}
if err := dao.Mdb.Create(node).Error; err != nil {
t.Fatalf("seed rpc_node: %v", err)
}
got, ok := resolveChainWsURL(mdb.NetworkEthereum, "[TEST]")
if !ok {
t.Fatalf("resolveChainWsURL() ok=false, want true")
}
if got != "wss://ethereum.example.com" {
t.Fatalf("resolveChainWsURL() = %q, want wss://ethereum.example.com", got)
}
}
func TestResolveChainWsURLDisabledRow(t *testing.T) {
cleanup := testutil.SetupTestDatabases(t)
defer cleanup()
node := &mdb.RpcNode{
Network: mdb.NetworkEthereum,
Url: "wss://disabled.example.com",
Type: mdb.RpcNodeTypeWs,
Weight: 1,
Enabled: true,
Status: mdb.RpcNodeStatusOk,
}
if err := dao.Mdb.Create(node).Error; err != nil {
t.Fatalf("seed rpc_node: %v", err)
}
if err := dao.Mdb.Model(node).Update("enabled", false).Error; err != nil {
t.Fatalf("disable rpc_node: %v", err)
}
if got, ok := resolveChainWsURL(mdb.NetworkEthereum, "[TEST]"); ok {
t.Fatalf("resolveChainWsURL() = (%q, true), want false", got)
}
}
+4 -19
View File
@@ -7,7 +7,6 @@ import (
"sync/atomic"
"time"
"github.com/assimon/luuu/config"
"github.com/assimon/luuu/model/data"
"github.com/assimon/luuu/model/mdb"
"github.com/assimon/luuu/model/service"
@@ -22,22 +21,6 @@ import (
// Transfer 事件签名 — ERC-20 signature, same on every EVM chain.
var transferEventHash = common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
const ethereumDefaultWsURL = "wss://ethereum.publicnode.com"
// resolveEthereumWsURL picks a healthy WS endpoint. Falls back to the
// legacy .env value (if set) before the shared default — keeps existing
// deployments working until the admin adds an rpc_nodes row.
func resolveEthereumWsURL() string {
node, err := data.SelectRpcNode(mdb.NetworkEthereum, mdb.RpcNodeTypeWs)
if err == nil && node != nil && node.ID > 0 {
return node.Url
}
if u := config.GetEthereumWsUrl(); u != "" {
return u
}
return ethereumDefaultWsURL
}
type ethRecipientSnapshot struct {
addrs map[string]struct{}
}
@@ -88,7 +71,10 @@ func runEthereumListener(contracts []common.Address) {
}
}()
wsURL := resolveEthereumWsURL()
wsURL, ok := resolveChainWsURL(mdb.NetworkEthereum, "[ETH-WS]")
if !ok {
return
}
log.Sugar.Infof("[ETH-WS] connecting to %s watching %d contract(s)", wsURL, len(contracts))
query := ethereum.FilterQuery{
@@ -145,4 +131,3 @@ func isWatchedEthRecipient(to common.Address) bool {
_, ok := snap.addrs[strings.ToLower(to.Hex())]
return ok
}
+4 -3
View File
@@ -18,8 +18,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
)
const plasmaDefaultWsURL = "wss://rpc.plasma.to"
type plasmaRecipientSnapshot struct {
addrs map[string]struct{}
}
@@ -67,7 +65,10 @@ func runPlasmaListener(contracts []common.Address) {
}
}()
wsURL := resolveChainWsURL(mdb.NetworkPlasma, plasmaDefaultWsURL)
wsURL, ok := resolveChainWsURL(mdb.NetworkPlasma, "[PLASMA-WS]")
if !ok {
return
}
log.Sugar.Infof("[PLASMA-WS] connecting to %s watching %d contract(s)", wsURL, len(contracts))
query := ethereum.FilterQuery{
+4 -3
View File
@@ -18,8 +18,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
)
const polygonDefaultWsURL = "wss://polygon-bor-rpc.publicnode.com"
type polygonRecipientSnapshot struct {
addrs map[string]struct{}
}
@@ -67,7 +65,10 @@ func runPolygonListener(contracts []common.Address) {
}
}()
wsURL := resolveChainWsURL(mdb.NetworkPolygon, polygonDefaultWsURL)
wsURL, ok := resolveChainWsURL(mdb.NetworkPolygon, "[POLYGON-WS]")
if !ok {
return
}
log.Sugar.Infof("[POLYGON-WS] connecting to %s watching %d contract(s)", wsURL, len(contracts))
query := ethereum.FilterQuery{