dione/node/node_dep_providers.go

406 lines
10 KiB
Go
Raw Normal View History

package node
import (
"context"
"crypto/rand"
"flag"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"github.com/Secured-Finance/dione/cache/inmemory"
"github.com/Secured-Finance/dione/cache/redis"
types2 "github.com/Secured-Finance/dione/blockchain/types"
"github.com/Secured-Finance/dione/rpc"
"github.com/Secured-Finance/dione/rpc/filecoin"
solana2 "github.com/Secured-Finance/dione/rpc/solana"
rtypes "github.com/Secured-Finance/dione/rpc/types"
"github.com/sirupsen/logrus"
"github.com/asaskevich/EventBus"
2021-06-04 21:18:06 +00:00
"github.com/Secured-Finance/dione/blockchain"
drand2 "github.com/Secured-Finance/dione/beacon/drand"
"github.com/libp2p/go-libp2p-core/protocol"
gorpc "github.com/libp2p/go-libp2p-gorpc"
"github.com/Secured-Finance/dione/blockchain/sync"
"github.com/Secured-Finance/dione/blockchain/pool"
"github.com/Secured-Finance/dione/cache"
"github.com/Secured-Finance/dione/config"
"github.com/Secured-Finance/dione/consensus"
"github.com/Secured-Finance/dione/ethclient"
"github.com/Secured-Finance/dione/pubsub"
"github.com/Secured-Finance/dione/types"
"github.com/Secured-Finance/dione/wallet"
pex "github.com/Secured-Finance/go-libp2p-pex"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/discovery"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multiaddr"
"golang.org/x/xerrors"
)
const (
DioneProtocolID = protocol.ID("/dione/1.0")
)
func provideCacheManager(cfg *config.Config) cache.CacheManager {
var backend cache.CacheManager
switch cfg.CacheType {
case config.CacheTypeInMemory:
backend = inmemory.NewCacheManager()
case config.CacheTypeRedis:
backend = redis.NewCacheManager(cfg)
default:
backend = inmemory.NewCacheManager()
}
return backend
}
func provideDrandBeacon(ps *pubsub.PubSubRouter, bus EventBus.Bus) *drand2.DrandBeacon {
db, err := drand2.NewDrandBeacon(ps.Pubsub, bus)
if err != nil {
logrus.Fatalf("Failed to setup drand beacon: %s", err)
}
logrus.Info("DRAND beacon subsystem has been initialized!")
return db
}
// FIXME: do we really need this?
func provideWallet(peerID peer.ID, privKey []byte) (*wallet.LocalWallet, error) {
// TODO make persistent keystore
kstore := wallet.NewMemKeyStore()
keyInfo := types.KeyInfo{
Type: types.KTEd25519,
PrivateKey: privKey,
}
kstore.Put(wallet.KNamePrefix+peerID.String(), keyInfo)
w, err := wallet.NewWallet(kstore)
if err != nil {
return nil, xerrors.Errorf("failed to setup wallet: %w", err)
}
return w, nil
}
func provideEthereumClient(config *config.Config) *ethclient.EthereumClient {
ethereum := ethclient.NewEthereumClient()
err := ethereum.Initialize(&config.Ethereum)
if err != nil {
logrus.Fatal(err)
}
logrus.WithField("ethAddress", ethereum.GetEthAddress().Hex()).Info("Ethereum client has been initialized!")
return ethereum
}
func providePubsubRouter(lhost host.Host, config *config.Config) *pubsub.PubSubRouter {
psb := pubsub.NewPubSubRouter(lhost, config.PubSub.ServiceTopicName, config.IsBootstrap)
logrus.Info("PubSub subsystem has been initialized!")
return psb
}
2021-07-11 00:32:58 +00:00
func provideConsensusManager(
h host.Host,
2021-07-11 00:32:58 +00:00
bus EventBus.Bus,
psb *pubsub.PubSubRouter,
miner *blockchain.Miner,
2021-07-11 00:32:58 +00:00
bc *blockchain.BlockChain,
ethClient *ethclient.EthereumClient,
privateKey crypto.PrivKey,
bp *consensus.ConsensusStatePool,
db *drand2.DrandBeacon,
2021-07-11 23:23:00 +00:00
mp *pool.Mempool,
2021-07-11 00:32:58 +00:00
) *consensus.PBFTConsensusManager {
c := consensus.NewPBFTConsensusManager(
2021-07-11 00:32:58 +00:00
bus,
psb,
privateKey,
ethClient,
miner,
bc,
bp,
db,
2021-07-11 23:23:00 +00:00
mp,
h.ID(),
2021-07-11 00:32:58 +00:00
)
logrus.Info("Consensus subsystem has been initialized!")
return c
}
func provideLibp2pHost(config *config.Config, privateKey crypto.PrivKey) host.Host {
listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", config.ListenAddr, config.ListenPort))
if err != nil {
logrus.Fatalf("Failed to parse multiaddress: %s", err.Error())
}
libp2pHost, err := libp2p.New(
context.TODO(),
libp2p.ListenAddrs(listenMultiAddr),
libp2p.Identity(privateKey),
)
if err != nil {
logrus.Fatal(err)
}
logrus.WithField(
"multiaddress",
fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s",
config.ListenAddr,
config.ListenPort,
libp2pHost.ID().Pretty(),
)).Info("Libp2p host has been initialized!")
return libp2pHost
}
func provideNetworkRPCHost(h host.Host) *gorpc.Server {
return gorpc.NewServer(h, DioneProtocolID)
}
func provideBootstrapAddrs(c *config.Config) []multiaddr.Multiaddr {
if c.IsBootstrap {
return nil
}
var bootstrapMaddrs []multiaddr.Multiaddr
for _, a := range c.BootstrapNodes {
maddr, err := multiaddr.NewMultiaddr(a)
if err != nil {
logrus.Fatalf("Invalid multiaddress of bootstrap node: %v", err)
}
bootstrapMaddrs = append(bootstrapMaddrs, maddr)
}
return bootstrapMaddrs
}
func providePeerDiscovery(baddrs []multiaddr.Multiaddr, h host.Host) discovery.Discovery {
pexDiscovery, err := pex.NewPEXDiscovery(h, baddrs, DefaultPEXUpdateTime)
if err != nil {
logrus.Fatalf("Failed to setup libp2p PEX discovery: %s", err.Error())
}
logrus.Info("Peer discovery subsystem has been initialized!")
return pexDiscovery
}
func provideBlockChain(config *config.Config, bus EventBus.Bus, miner *blockchain.Miner, db *drand2.DrandBeacon) *blockchain.BlockChain {
bc, err := blockchain.NewBlockChain(config.Blockchain.DatabasePath, bus, miner, db)
if err != nil {
logrus.Fatalf("Failed to initialize blockchain storage: %s", err.Error())
}
logrus.Info("Blockchain storage has been successfully initialized!")
return bc
}
func provideMempool(bus EventBus.Bus) *pool.Mempool {
mp, err := pool.NewMempool(bus)
if err != nil {
logrus.Fatalf("Failed to initialize mempool: %s", err.Error())
}
logrus.Info("Mempool has been successfully initialized!")
return mp
}
func provideSyncManager(
bus EventBus.Bus,
bp *blockchain.BlockChain,
mp *pool.Mempool,
c *gorpc.Client,
bootstrapAddresses []multiaddr.Multiaddr,
psb *pubsub.PubSubRouter,
) sync.SyncManager {
bootstrapPeerID := peer.ID("")
if bootstrapAddresses != nil {
addr, err := peer.AddrInfoFromP2pAddr(bootstrapAddresses[0]) // FIXME
if err != nil {
logrus.Fatal(err)
}
bootstrapPeerID = addr.ID
}
sm := sync.NewSyncManager(bus, bp, mp, c, bootstrapPeerID, psb)
logrus.Info("Blockchain sync subsystem has been successfully initialized!")
return sm
}
func provideDirectRPCClient(h host.Host) *gorpc.Client {
return gorpc.NewClient(h, DioneProtocolID)
}
2021-07-11 00:32:58 +00:00
func provideNetworkService(bp *blockchain.BlockChain, mp *pool.Mempool) *NetworkService {
ns := NewNetworkService(bp, mp)
logrus.Info("Direct RPC has been successfully initialized!")
return ns
}
func provideBlockPool(mp *pool.Mempool, bus EventBus.Bus, config *config.Config) *consensus.ConsensusStatePool {
bp, err := consensus.NewConsensusRoundPool(mp, bus, config.ConsensusMinApprovals)
if err != nil {
logrus.Fatalf("Failed to initialize blockpool: %s", err.Error())
}
logrus.Info("Consensus state pool has been successfully initialized!")
return bp
2021-07-11 00:32:58 +00:00
}
func provideEventBus() EventBus.Bus {
return EventBus.New()
}
func provideAppFlags() *AppFlags {
var flags AppFlags
flag.StringVar(&flags.ConfigPath, "config", "", "Path to config")
flag.BoolVar(&flags.Verbose, "verbose", false, "Verbose logging")
flag.Parse()
return &flags
}
func provideConfig(flags *AppFlags) *config.Config {
if flags.ConfigPath == "" {
logrus.Fatal("no config path provided")
}
cfg, err := config.NewConfig(flags.ConfigPath)
if err != nil {
logrus.Fatalf("failed to load config: %v", err)
}
return cfg
}
func providePrivateKey(cfg *config.Config) crypto.PrivKey {
var privateKey crypto.PrivKey
if _, err := os.Stat(cfg.PrivateKeyPath); os.IsNotExist(err) {
privateKey, err = generatePrivateKey()
if err != nil {
logrus.Fatal(err)
}
dirName := filepath.Dir(cfg.PrivateKeyPath)
if _, err := os.Stat(dirName); os.IsNotExist(err) {
err := os.MkdirAll(dirName, 0755)
if err != nil {
logrus.Fatalf("Cannot create private key file: %s", err.Error())
}
}
f, err := os.Create(cfg.PrivateKeyPath)
if err != nil {
logrus.Fatalf("Cannot create private key file: %s, ", err)
}
r, err := privateKey.Raw()
if err != nil {
logrus.Fatal(err)
}
_, err = f.Write(r)
if err != nil {
logrus.Fatal(err)
}
} else {
pkey, err := ioutil.ReadFile(cfg.PrivateKeyPath)
if err != nil {
logrus.Fatal(err)
}
privateKey, err = crypto.UnmarshalEd25519PrivateKey(pkey)
if err != nil {
logrus.Fatal(err)
}
}
return privateKey
}
func generatePrivateKey() (crypto.PrivKey, error) {
r := rand.Reader
// Creates a new RSA key pair for this host.
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, r)
if err != nil {
return nil, err
}
return prvKey, nil
}
func configureDirectRPC(rpcServer *gorpc.Server, ns *NetworkService) {
err := rpcServer.Register(ns)
if err != nil {
logrus.Fatal(err)
}
}
func configureLogger(flags *AppFlags) {
logrus.SetReportCaller(true)
logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
filename := path.Base(f.File)
return "", fmt.Sprintf("%s:%d:", filename, f.Line)
},
})
if flags.Verbose {
logrus.SetLevel(logrus.DebugLevel)
} else {
logrus.SetLevel(logrus.InfoLevel)
}
}
func configureForeignBlockchainRPC() {
fc := filecoin.NewLotusClient()
rpc.RegisterRPC(rtypes.RPCTypeFilecoin, map[string]func(string) ([]byte, error){
"getTransaction": fc.GetTransaction,
"getBlock": fc.GetBlock,
})
sl := solana2.NewSolanaClient()
rpc.RegisterRPC(rtypes.RPCTypeSolana, map[string]func(string) ([]byte, error){
"getTransaction": sl.GetTransaction,
})
logrus.Info("Foreign Blockchain RPC clients has been successfully configured!")
}
func configureMiner(m *blockchain.Miner, b *blockchain.BlockChain) {
m.SetBlockchainInstance(b)
}
func initializeBlockchain(bc *blockchain.BlockChain) {
_, err := bc.GetLatestBlockHeight()
if err == blockchain.ErrLatestHeightNil {
gBlock := types2.GenesisBlock()
err = bc.StoreBlock(gBlock) // commit genesis block
if err != nil {
logrus.Fatal(err)
}
logrus.Info("Committed genesis block")
}
}