erigon-pulse/cmd/tester/main.go

226 lines
5.7 KiB
Go
Raw Normal View History

package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"os/signal"
"runtime"
"sort"
"syscall"
"github.com/ledgerwatch/turbo-geth/cmd/utils"
2020-06-15 14:39:07 +00:00
"github.com/ledgerwatch/turbo-geth/console/prompt"
"github.com/ledgerwatch/turbo-geth/crypto"
"github.com/ledgerwatch/turbo-geth/eth"
"github.com/ledgerwatch/turbo-geth/internal/debug"
2020-08-07 12:25:40 +00:00
ff "github.com/ledgerwatch/turbo-geth/internal/flags"
"github.com/ledgerwatch/turbo-geth/log"
"github.com/ledgerwatch/turbo-geth/p2p"
"github.com/ledgerwatch/turbo-geth/p2p/enode"
"github.com/urfave/cli"
)
var (
// Git SHA1 commit hash of the release (set via linker flags)
gitCommit = ""
gitDate = ""
// The app that holds all commands and flags.
2020-08-07 12:25:40 +00:00
app = ff.NewApp(gitCommit, gitDate, "Ethereum Tester")
// flags that configure the node
VerbosityFlag = cli.IntFlag{
Name: "verbosity",
Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
Value: 3,
}
flags = []cli.Flag{VerbosityFlag}
)
func init() {
// Initialize the CLI app and start TurboGeth
app.Action = tester
app.HideVersion = true // we have a command to print the version
app.Copyright = "Copyright 2020 The turbo-geth Authors"
app.Commands = []cli.Command{}
sort.Sort(cli.CommandsByName(app.Commands))
app.Flags = append(app.Flags, flags...)
app.Before = func(ctx *cli.Context) error {
log.SetupDefaultTerminalLogger(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)), "", "")
runtime.GOMAXPROCS(runtime.NumCPU())
2020-02-21 15:25:11 +00:00
if err := debug.Setup(ctx); err != nil {
return err
}
return nil
}
app.After = func(ctx *cli.Context) error {
debug.Exit()
2020-06-15 14:39:07 +00:00
prompt.Stdin.Close() // Resets terminal mode.
return nil
}
app.Commands = []cli.Command{
{
Action: utils.MigrateFlags(genesisCmd),
Name: "genesis",
Usage: "Produce genesis.json file for geth",
},
}
}
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func rootContext() context.Context {
ctx, cancel := context.WithCancel(context.Background())
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
defer signal.Stop(ch)
select {
case <-ch:
log.Info("Got interrupt, shutting down...")
case <-ctx.Done():
}
cancel()
}()
return ctx
}
func tester(cliCtx *cli.Context) error {
ctx := rootContext()
nodeToConnect, err := getTargetAddr(cliCtx)
if err != nil {
return err
}
blockGen, err := NewBlockGenerator(ctx, "blocks", 50000)
if err != nil {
panic(fmt.Sprintf("Failed to create block generator: %v", err))
}
defer blockGen.Close()
forkBase := uint64(49998)
forkHeight := uint64(5)
forkGen, err := NewForkGenerator(ctx, blockGen, "forkblocks", forkBase, forkHeight)
if err != nil {
panic(fmt.Sprintf("Failed to create fork generator: %v", err))
}
defer forkGen.Close()
tp1 := NewTesterProtocol("tp1", true /* fork */, true /* debug */)
tp1.blockFeeder = blockGen
tp1.forkBase = forkBase
tp1.forkHeight = forkHeight
tp1.forkFeeder = forkGen
tp1.protocolVersion = uint32(eth.ProtocolVersions[0])
tp1.networkId = 1 // Mainnet
tp1.genesisBlockHash = forkGen.Genesis().Hash()
server1 := makeP2PServer(ctx, tp1, []string{eth.ProtocolName, eth.DebugName})
// Add protocol
if err := server1.Start(); err != nil {
panic(fmt.Errorf("could not start server 1: %w", err))
}
server1.AddPeer(nodeToConnect)
tp2 := NewTesterProtocol("tp2", false, false)
tp2.blockFeeder = blockGen
tp2.protocolVersion = uint32(eth.ProtocolVersions[0])
tp2.networkId = 1 // Mainnet
tp2.genesisBlockHash = blockGen.Genesis().Hash()
server2 := makeP2PServer(ctx, tp2, []string{eth.ProtocolName})
tp1.WaitForFork(ctx)
// Add protocol
if err := server2.Start(); err != nil {
panic(fmt.Errorf("could not start server 2: %w", err))
}
server2.AddPeer(nodeToConnect)
<-ctx.Done()
return nil
}
func genesisCmd(cliCtx *cli.Context) error {
res, err := json.Marshal(genesis())
if err != nil {
return err
}
_, err = fmt.Fprintf(os.Stdout, string(res))
if err != nil {
return err
}
return nil
}
func makeP2PServer(ctx context.Context, tp *TesterProtocol, protocols []string) *p2p.Server {
serverKey, err := crypto.GenerateKey()
if err != nil {
panic(fmt.Sprintf("Failed to generate server key: %v", err))
}
p2pConfig := p2p.Config{}
p2pConfig.PrivateKey = serverKey
p2pConfig.Name = "geth tester"
p2pConfig.Logger = log.New()
p2pConfig.MaxPeers = 1
p2pConfig.Protocols = []p2p.Protocol{}
pMap := map[string]p2p.Protocol{
eth.ProtocolName: {
Name: eth.ProtocolName,
Version: eth.ProtocolVersions[0],
Length: eth.ProtocolLengths[eth.ProtocolVersions[0]],
Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
return tp.protocolRun(ctx, peer, rw)
},
},
eth.DebugName: {
Name: eth.DebugName,
Version: eth.DebugVersions[0],
Length: eth.DebugLengths[eth.DebugVersions[0]],
Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
return tp.debugProtocolRun(ctx, peer, rw)
},
},
}
for _, protocolName := range protocols {
p2pConfig.Protocols = append(p2pConfig.Protocols, pMap[protocolName])
}
return &p2p.Server{Config: p2pConfig}
}
func getTargetAddr(cliCtx *cli.Context) (*enode.Node, error) {
var enodeAddress string
if len(cliCtx.Args()) < 1 {
addr, err := ioutil.ReadFile(p2p.EnodeAddressFileName)
if err != nil {
return nil, err
}
enodeAddress = string(addr)
} else {
enodeAddress = cliCtx.Args()[0]
}
if enodeAddress == "" {
return nil, errors.New("Usage: tester <enode>\n")
}
nodeToConnect, err := enode.ParseV4(enodeAddress)
if err != nil {
return nil, fmt.Errorf("could not parse the node info: %w", err)
}
fmt.Printf("Parsed node: %s, IP: %s\n", nodeToConnect, nodeToConnect.IP())
return nodeToConnect, nil
}