2020-08-03 20:01:38 +00:00
|
|
|
package node
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/rand"
|
2020-08-19 19:26:48 +00:00
|
|
|
"flag"
|
2020-08-03 20:01:38 +00:00
|
|
|
"fmt"
|
2020-10-20 18:18:36 +00:00
|
|
|
"sync"
|
2020-08-03 20:01:38 +00:00
|
|
|
|
|
|
|
"github.com/Secured-Finance/p2p-oracle-node/config"
|
2020-08-07 02:42:09 +00:00
|
|
|
"github.com/Secured-Finance/p2p-oracle-node/rpc"
|
|
|
|
"github.com/Secured-Finance/p2p-oracle-node/rpcclient"
|
2020-08-03 20:01:38 +00:00
|
|
|
"github.com/ipfs/go-log"
|
|
|
|
"github.com/libp2p/go-libp2p"
|
|
|
|
crypto "github.com/libp2p/go-libp2p-core/crypto"
|
|
|
|
"github.com/libp2p/go-libp2p-core/host"
|
2020-10-20 18:18:36 +00:00
|
|
|
peer "github.com/libp2p/go-libp2p-core/peer"
|
|
|
|
discovery "github.com/libp2p/go-libp2p-discovery"
|
|
|
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
|
|
|
peerstore "github.com/libp2p/go-libp2p-peerstore"
|
2020-08-03 20:01:38 +00:00
|
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
|
|
|
"github.com/multiformats/go-multiaddr"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Node struct {
|
|
|
|
Host host.Host
|
|
|
|
PubSub *pubsub.PubSub
|
|
|
|
GlobalCtx context.Context
|
|
|
|
GlobalCtxCancel context.CancelFunc
|
|
|
|
OracleTopic string
|
|
|
|
Config *config.Config
|
|
|
|
Logger *log.ZapEventLogger
|
2020-08-07 02:42:09 +00:00
|
|
|
Lotus *rpc.LotusClient
|
|
|
|
Ethereum *rpcclient.EthereumClient
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 19:26:48 +00:00
|
|
|
func NewNode(configPath string) (*Node, error) {
|
|
|
|
cfg, err := config.NewConfig(configPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-03 20:01:38 +00:00
|
|
|
node := &Node{
|
2020-10-20 18:18:36 +00:00
|
|
|
OracleTopic: "p2p_oracle",
|
|
|
|
Config: cfg,
|
|
|
|
Logger: log.Logger("node"),
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
2020-08-06 21:47:58 +00:00
|
|
|
log.SetAllLoggers(log.LevelInfo)
|
2020-08-03 20:01:38 +00:00
|
|
|
|
2020-08-19 19:26:48 +00:00
|
|
|
return node, nil
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 18:18:36 +00:00
|
|
|
func (n *Node) setupNode(ctx context.Context, prvKey crypto.PrivKey) {
|
|
|
|
listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%s", n.Config.ListenAddr, n.Config.ListenPort))
|
2020-08-03 20:01:38 +00:00
|
|
|
if err != nil {
|
2020-10-20 18:18:36 +00:00
|
|
|
n.Logger.Fatal("Failed to generate new node multiaddress:", err)
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
host, err := libp2p.New(
|
|
|
|
ctx,
|
|
|
|
libp2p.ListenAddrs(listenMultiAddr),
|
|
|
|
libp2p.Identity(prvKey),
|
|
|
|
)
|
|
|
|
if err != nil {
|
2020-10-20 18:18:36 +00:00
|
|
|
n.Logger.Fatal("Failed to set a new libp2p node:", err)
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
2020-10-20 18:18:36 +00:00
|
|
|
n.Host = host
|
|
|
|
n.bootstrapLibp2pHost(context.TODO())
|
2020-10-20 18:58:24 +00:00
|
|
|
n.setupEthereumClient()
|
2020-10-20 18:18:36 +00:00
|
|
|
n.setupFilecoinClient()
|
|
|
|
//n.startPubSub(ctx, host)
|
|
|
|
}
|
|
|
|
|
2020-10-20 18:58:24 +00:00
|
|
|
func (n *Node) setupEthereumClient() error {
|
2020-10-20 18:18:36 +00:00
|
|
|
ethereum := rpcclient.NewEthereumClient()
|
|
|
|
n.Ethereum = ethereum
|
|
|
|
return ethereum.Initialize(context.Background(),
|
2020-10-20 18:58:24 +00:00
|
|
|
n.Config.Ethereum.GatewayAddress,
|
|
|
|
n.Config.Ethereum.PrivateKey,
|
|
|
|
n.Config.Ethereum.OracleEmitterContractAddress,
|
|
|
|
n.Config.Ethereum.AggregatorContractAddress,
|
2020-10-20 18:18:36 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) setupFilecoinClient() {
|
|
|
|
lotus := rpc.NewLotusClient(n.Config.Filecoin.LotusHost, n.Config.Filecoin.LotusToken)
|
|
|
|
n.Lotus = lotus
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) bootstrapLibp2pHost(ctx context.Context) {
|
|
|
|
kademliaDHT, err := dht.New(context.Background(), n.Host)
|
|
|
|
if err != nil {
|
|
|
|
n.Logger.Fatal("Failed to create new DHT instance: ", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = kademliaDHT.Bootstrap(context.Background()); err != nil {
|
|
|
|
n.Logger.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !n.Config.Bootstrap {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
bootstrapMultiaddr, err := multiaddr.NewMultiaddr(n.Config.BootstrapNodeMultiaddr)
|
|
|
|
if err != nil {
|
|
|
|
n.Logger.Fatal(err)
|
|
|
|
}
|
|
|
|
peerinfo, _ := peer.AddrInfoFromP2pAddr(bootstrapMultiaddr)
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
if err := n.Host.Connect(context.Background(), *peerinfo); err != nil {
|
|
|
|
n.Logger.Fatal(err)
|
|
|
|
}
|
|
|
|
n.Logger.Info("Connection established with bootstrap node:", *peerinfo)
|
|
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
n.Logger.Info("Announcing ourselves...")
|
|
|
|
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT)
|
|
|
|
discovery.Advertise(context.Background(), routingDiscovery, n.Config.Rendezvous)
|
|
|
|
n.Logger.Info("Successfully announced!")
|
|
|
|
|
|
|
|
// Randezvous string = service tag
|
|
|
|
// Disvover all peers with our service (all ms devices)
|
|
|
|
n.Logger.Info("Searching for other peers...")
|
|
|
|
peerChan, err := routingDiscovery.FindPeers(context.Background(), n.Config.Rendezvous)
|
|
|
|
if err != nil {
|
|
|
|
n.Logger.Fatal("Failed to find new peers, exiting...", err)
|
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
MainLoop:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
break MainLoop
|
|
|
|
case newPeer := <-peerChan:
|
|
|
|
{
|
|
|
|
n.Logger.Info("Found peer:", newPeer, ", put it to the peerstore")
|
|
|
|
n.Host.Peerstore().AddAddr(newPeer.ID, newPeer.Addrs[0], peerstore.PermanentAddrTTL)
|
|
|
|
// Connect to the peer
|
|
|
|
if err := n.Host.Connect(ctx, newPeer); err != nil {
|
|
|
|
n.Logger.Warn("Connection failed: ", err)
|
|
|
|
}
|
|
|
|
n.Logger.Info("Connected to: ", newPeer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 19:26:48 +00:00
|
|
|
func Start() error {
|
|
|
|
configPath := flag.String("config", "", "Path to config")
|
|
|
|
verbose := flag.Bool("verbose", false, "Verbose logging")
|
|
|
|
flag.Parse()
|
2020-08-03 20:01:38 +00:00
|
|
|
|
2020-08-19 19:26:48 +00:00
|
|
|
if *configPath == "" {
|
|
|
|
return fmt.Errorf("no config path provided")
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 19:26:48 +00:00
|
|
|
node, err := NewNode(*configPath)
|
|
|
|
if *verbose {
|
|
|
|
log.SetAllLoggers(log.LevelDebug)
|
|
|
|
} else {
|
|
|
|
log.SetAllLoggers(log.LevelInfo)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
log.Logger("node").Panic(err)
|
|
|
|
}
|
2020-08-03 20:01:38 +00:00
|
|
|
|
2020-10-20 18:18:36 +00:00
|
|
|
privKey, err := generatePrivateKey()
|
2020-08-03 20:01:38 +00:00
|
|
|
if err != nil {
|
|
|
|
node.Logger.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
|
|
|
node.GlobalCtx = ctx
|
|
|
|
node.GlobalCtxCancel = ctxCancel
|
|
|
|
|
2020-10-20 18:18:36 +00:00
|
|
|
node.setupNode(ctx, privKey)
|
2020-08-19 19:26:48 +00:00
|
|
|
return nil
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
2020-10-20 18:18:36 +00:00
|
|
|
|
|
|
|
func generatePrivateKey() (crypto.PrivKey, error) {
|
|
|
|
r := rand.Reader
|
|
|
|
// Creates a new RSA key pair for this host.
|
|
|
|
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return prvKey, nil
|
|
|
|
}
|