go-ethereum/cmd/shisui/main.go
Chen Kai 6795c90755 feat:rm get internal ip
Signed-off-by: Chen Kai <281165273grape@gmail.com>
2024-06-13 13:37:40 +08:00

308 lines
7.9 KiB
Go

package main
import (
"crypto/ecdsa"
"database/sql"
"fmt"
"net"
"net/http"
"path"
"slices"
"strings"
"os"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discover/portalwire"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/portalnetwork/beacon"
"github.com/ethereum/go-ethereum/portalnetwork/history"
"github.com/ethereum/go-ethereum/portalnetwork/storage"
"github.com/ethereum/go-ethereum/portalnetwork/web3"
"github.com/ethereum/go-ethereum/rpc"
_ "github.com/mattn/go-sqlite3"
"github.com/protolambda/zrnt/eth2/configs"
"github.com/urfave/cli/v2"
)
type Config struct {
Protocol *discover.PortalProtocolConfig
PrivateKey *ecdsa.PrivateKey
RpcAddr string
DataDir string
DataCapacity uint64
LogLevel int
Networks []string
}
var app = flags.NewApp("the go-portal-network command line interface")
var (
portalProtocolFlags = []cli.Flag{
utils.PortalNATFlag,
utils.PortalUDPPortFlag,
utils.PortalBootNodesFlag,
utils.PortalPrivateKeyFlag,
utils.PortalNetworksFlag,
}
historyRpcFlags = []cli.Flag{
utils.PortalRPCListenAddrFlag,
utils.PortalRPCPortFlag,
utils.PortalDataDirFlag,
utils.PortalDataCapacityFlag,
utils.PortalLogLevelFlag,
}
)
func init() {
app.Action = shisui
app.Flags = flags.Merge(portalProtocolFlags, historyRpcFlags)
flags.AutoEnvVars(app.Flags, "SHISUI")
}
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func shisui(ctx *cli.Context) error {
config, err := getPortalConfig(ctx)
if err != nil {
return nil
}
setDefaultLogger(*config)
addr, err := net.ResolveUDPAddr("udp", config.Protocol.ListenAddr)
if err != nil {
return err
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
return err
}
return startPortalRpcServer(*config, conn, config.RpcAddr)
}
func setDefaultLogger(config Config) {
glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, true))
slogVerbosity := log.FromLegacyLevel(config.LogLevel)
glogger.Verbosity(slogVerbosity)
defaultLogger := log.NewLogger(glogger)
log.SetDefault(defaultLogger)
}
func startPortalRpcServer(config Config, conn discover.UDPConn, addr string) error {
discV5, localNode, err := initDiscV5(config, conn)
if err != nil {
return err
}
server := rpc.NewServer()
discV5API := discover.NewDiscV5API(discV5)
err = server.RegisterName("discv5", discV5API)
if err != nil {
return err
}
api := &web3.API{}
err = server.RegisterName("web3", api)
if err != nil {
return err
}
if slices.Contains(config.Networks, portalwire.HistoryNetworkName) {
err = initHistory(config, server, conn, localNode, discV5)
if err != nil {
return err
}
}
if slices.Contains(config.Networks, portalwire.BeaconNetworkName) {
err = initBeacon(config, server, conn, localNode, discV5)
if err != nil {
return err
}
}
httpServer := &http.Server{
Addr: addr,
Handler: server,
}
return httpServer.ListenAndServe()
}
func initDiscV5(config Config, conn discover.UDPConn) (*discover.UDPv5, *enode.LocalNode, error) {
discCfg := discover.Config{
PrivateKey: config.PrivateKey,
NetRestrict: config.Protocol.NetRestrict,
Bootnodes: config.Protocol.BootstrapNodes,
Log: log.New("protocol", "discV5"),
}
nodeDB, err := enode.OpenDB(config.Protocol.NodeDBPath)
if err != nil {
return nil, nil, err
}
localNode := enode.NewLocalNode(nodeDB, config.PrivateKey)
localNode.SetFallbackIP(net.IP{127, 0, 0, 1})
localNode.Set(discover.Tag)
discV5, err := discover.ListenV5(conn, localNode, discCfg)
if err != nil {
return nil, nil, err
}
return discV5, localNode, nil
}
func initHistory(config Config, server *rpc.Server, conn discover.UDPConn, localNode *enode.LocalNode, discV5 *discover.UDPv5) error {
db, err := history.NewDB(config.DataDir)
if err != nil {
return err
}
contentStorage, err := history.NewHistoryStorage(storage.PortalStorageConfig{
StorageCapacityMB: config.DataCapacity,
DB: db,
NodeId: localNode.ID(),
})
if err != nil {
return err
}
contentQueue := make(chan *discover.ContentElement, 50)
protocol, err := discover.NewPortalProtocol(config.Protocol, string(portalwire.HistoryNetwork), config.PrivateKey, conn, localNode, discV5, contentStorage, contentQueue)
if err != nil {
return err
}
historyAPI := discover.NewPortalAPI(protocol)
historyNetworkAPI := history.NewHistoryNetworkAPI(historyAPI)
err = server.RegisterName("portal", historyNetworkAPI)
if err != nil {
return err
}
accumulator, err := history.NewMasterAccumulator()
if err != nil {
return err
}
historyNetwork := history.NewHistoryNetwork(protocol, &accumulator)
return historyNetwork.Start()
}
func initBeacon(config Config, server *rpc.Server, conn discover.UDPConn, localNode *enode.LocalNode, discV5 *discover.UDPv5) error {
dbPath := path.Join(config.DataDir, "beacon")
err := os.MkdirAll(dbPath, 0755)
if err != nil {
return err
}
sqlDb, err := sql.Open("sqlite3", path.Join(dbPath, "beacon.sqlite"))
if err != nil {
return err
}
contentStorage, err := beacon.NewBeaconStorage(storage.PortalStorageConfig{
StorageCapacityMB: config.DataCapacity,
DB: sqlDb,
NodeId: localNode.ID(),
Spec: configs.Mainnet,
})
if err != nil {
return err
}
contentQueue := make(chan *discover.ContentElement, 50)
protocol, err := discover.NewPortalProtocol(config.Protocol, string(portalwire.BeaconLightClientNetwork), config.PrivateKey, conn, localNode, discV5, contentStorage, contentQueue)
if err != nil {
return err
}
portalApi := discover.NewPortalAPI(protocol)
beaconAPI := beacon.NewBeaconNetworkAPI(portalApi)
err = server.RegisterName("portal", beaconAPI)
if err != nil {
return err
}
beaconNetwork := beacon.NewBeaconNetwork(protocol)
return beaconNetwork.Start()
}
func getPortalConfig(ctx *cli.Context) (*Config, error) {
config := &Config{
Protocol: discover.DefaultPortalProtocolConfig(),
}
err := setPrivateKey(ctx, config)
if err != nil {
return config, err
}
httpAddr := ctx.String(utils.PortalRPCListenAddrFlag.Name)
httpPort := ctx.String(utils.PortalRPCPortFlag.Name)
config.RpcAddr = net.JoinHostPort(httpAddr, httpPort)
config.DataDir = ctx.String(utils.PortalDataDirFlag.Name)
config.DataCapacity = ctx.Uint64(utils.PortalDataCapacityFlag.Name)
config.LogLevel = ctx.Int(utils.PortalLogLevelFlag.Name)
port := ctx.String(utils.PortalUDPPortFlag.Name)
if !strings.HasPrefix(port, ":") {
config.Protocol.ListenAddr = ":" + port
} else {
config.Protocol.ListenAddr = port
}
natString := ctx.String(utils.PortalNATFlag.Name)
if natString != "" {
natInterface, err := nat.Parse(natString)
if err != nil {
return config, err
}
config.Protocol.NAT = natInterface
}
bootNodes := ctx.StringSlice(utils.PortalBootNodesFlag.Name)
if len(bootNodes) > 0 {
for _, node := range bootNodes {
bootNode := new(enode.Node)
err = bootNode.UnmarshalText([]byte(node))
if err != nil {
return config, err
}
config.Protocol.BootstrapNodes = append(config.Protocol.BootstrapNodes, bootNode)
}
}
config.Networks = ctx.StringSlice(utils.PortalNetworksFlag.Name)
return config, nil
}
func setPrivateKey(ctx *cli.Context, config *Config) error {
var privateKey *ecdsa.PrivateKey
var err error
keyStr := ctx.String(utils.PortalPrivateKeyFlag.Name)
if keyStr != "" {
keyBytes, err := hexutil.Decode(keyStr)
if err != nil {
return err
}
privateKey, err = crypto.ToECDSA(keyBytes)
if err != nil {
return err
}
} else {
privateKey, err = crypto.GenerateKey()
if err != nil {
return err
}
}
config.PrivateKey = privateKey
return nil
}