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-11-15 10:11:07 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2020-10-21 19:54:40 +00:00
|
|
|
"time"
|
2020-08-03 20:01:38 +00:00
|
|
|
|
2020-11-18 18:33:03 +00:00
|
|
|
solana2 "github.com/Secured-Finance/dione/rpc/solana"
|
|
|
|
|
|
|
|
"github.com/Secured-Finance/dione/rpc/filecoin"
|
|
|
|
|
2020-11-14 00:32:50 +00:00
|
|
|
"github.com/Secured-Finance/dione/types"
|
|
|
|
|
|
|
|
"github.com/Secured-Finance/dione/wallet"
|
|
|
|
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
|
|
|
"github.com/Secured-Finance/dione/beacon"
|
|
|
|
|
2020-11-13 15:51:23 +00:00
|
|
|
pex "github.com/Secured-Finance/go-libp2p-pex"
|
|
|
|
|
2020-10-21 19:54:40 +00:00
|
|
|
"github.com/Secured-Finance/dione/config"
|
|
|
|
"github.com/Secured-Finance/dione/consensus"
|
2020-11-13 15:51:23 +00:00
|
|
|
"github.com/Secured-Finance/dione/ethclient"
|
2020-11-18 19:53:52 +00:00
|
|
|
"github.com/Secured-Finance/dione/pubsub"
|
2020-08-03 20:01:38 +00:00
|
|
|
"github.com/libp2p/go-libp2p"
|
|
|
|
crypto "github.com/libp2p/go-libp2p-core/crypto"
|
|
|
|
"github.com/libp2p/go-libp2p-core/host"
|
|
|
|
"github.com/multiformats/go-multiaddr"
|
2020-10-21 20:36:05 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2020-08-03 20:01:38 +00:00
|
|
|
)
|
|
|
|
|
2020-11-04 17:46:35 +00:00
|
|
|
const (
|
2020-11-15 10:11:07 +00:00
|
|
|
DefaultPEXUpdateTime = 6 * time.Second
|
2020-11-04 17:46:35 +00:00
|
|
|
)
|
|
|
|
|
2020-08-03 20:01:38 +00:00
|
|
|
type Node struct {
|
2020-10-21 19:54:40 +00:00
|
|
|
Host host.Host
|
2020-11-18 19:53:52 +00:00
|
|
|
PubSubRouter *pubsub.PubSubRouter
|
2020-10-21 19:54:40 +00:00
|
|
|
GlobalCtx context.Context
|
|
|
|
GlobalCtxCancel context.CancelFunc
|
|
|
|
OracleTopic string
|
|
|
|
Config *config.Config
|
2020-11-18 18:33:03 +00:00
|
|
|
Lotus *filecoin.LotusClient
|
2020-11-12 14:18:30 +00:00
|
|
|
Ethereum *ethclient.EthereumClient
|
2020-11-18 18:33:03 +00:00
|
|
|
Solana *solana2.SolanaClient
|
2020-10-21 19:54:40 +00:00
|
|
|
ConsensusManager *consensus.PBFTConsensusManager
|
2020-11-14 00:32:50 +00:00
|
|
|
Miner *consensus.Miner
|
|
|
|
Beacon beacon.BeaconNetworks
|
|
|
|
Wallet *wallet.LocalWallet
|
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-21 19:54:40 +00:00
|
|
|
OracleTopic: "dione",
|
2020-10-20 18:18:36 +00:00
|
|
|
Config: cfg,
|
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-11-04 18:17:01 +00:00
|
|
|
func (n *Node) setupNode(ctx context.Context, prvKey crypto.PrivKey, pexDiscoveryUpdateTime time.Duration) {
|
2020-11-04 17:46:35 +00:00
|
|
|
n.setupLibp2pHost(context.TODO(), prvKey, pexDiscoveryUpdateTime)
|
2020-10-21 19:54:40 +00:00
|
|
|
//n.setupFilecoinClient()
|
2020-11-14 00:32:50 +00:00
|
|
|
err := n.setupEthereumClient()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
2020-11-15 05:59:46 +00:00
|
|
|
n.setupSolanaClient()
|
2020-10-21 19:54:40 +00:00
|
|
|
n.setupPubsub()
|
2020-11-15 13:46:58 +00:00
|
|
|
err = n.setupConsensusManager(prvKey, n.Config.ConsensusMinApprovals)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatalf("Failed to setup consensus manager: %w", err)
|
|
|
|
}
|
2020-11-14 00:32:50 +00:00
|
|
|
err = n.setupBeacon()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
|
|
|
err = n.setupWallet(prvKey)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
|
|
|
err = n.setupMiner()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
2020-11-15 05:59:46 +00:00
|
|
|
n.subscribeOnEthContracts(ctx)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 14:18:30 +00:00
|
|
|
func (n *Node) setupMiner() error {
|
2020-11-15 05:59:46 +00:00
|
|
|
n.Miner = consensus.NewMiner(n.Host.ID(), *n.Ethereum.GetEthAddress(), n.Wallet, n.Beacon, n.Ethereum, n.Solana)
|
2020-11-14 00:32:50 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) setupBeacon() error {
|
|
|
|
beacon, err := n.NewBeaconClient()
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to setup beacon: %w", err)
|
|
|
|
}
|
|
|
|
n.Beacon = beacon
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) setupWallet(privKey crypto.PrivKey) error {
|
|
|
|
// TODO make persistent keystore
|
|
|
|
kstore := wallet.NewMemKeyStore()
|
|
|
|
pKeyBytes, err := privKey.Raw()
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to get raw private key: %w", err)
|
|
|
|
}
|
|
|
|
keyInfo := types.KeyInfo{
|
|
|
|
Type: types.KTEd25519,
|
|
|
|
PrivateKey: pKeyBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
kstore.Put(wallet.KNamePrefix+n.Host.ID().String(), keyInfo)
|
|
|
|
w, err := wallet.NewWallet(kstore)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to setup wallet: %w", err)
|
|
|
|
}
|
|
|
|
n.Wallet = w
|
2020-11-12 14:18:30 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-20 18:58:24 +00:00
|
|
|
func (n *Node) setupEthereumClient() error {
|
2020-11-12 14:18:30 +00:00
|
|
|
ethereum := ethclient.NewEthereumClient()
|
2020-10-20 18:18:36 +00:00
|
|
|
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-11-15 05:59:46 +00:00
|
|
|
n.Config.Ethereum.DioneStakingContractAddress,
|
2020-10-20 18:18:36 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) setupFilecoinClient() {
|
2020-11-18 18:33:03 +00:00
|
|
|
lotus := filecoin.NewLotusClient(n.Config.Filecoin.LotusHost, n.Config.Filecoin.LotusToken)
|
2020-10-20 18:18:36 +00:00
|
|
|
n.Lotus = lotus
|
|
|
|
}
|
|
|
|
|
2020-11-14 11:25:14 +00:00
|
|
|
func (n *Node) setupSolanaClient() {
|
2020-11-18 18:33:03 +00:00
|
|
|
solana := solana2.NewSolanaClient()
|
2020-11-14 11:25:14 +00:00
|
|
|
n.Solana = solana
|
|
|
|
}
|
|
|
|
|
2020-10-21 19:54:40 +00:00
|
|
|
func (n *Node) setupPubsub() {
|
2020-11-18 19:53:52 +00:00
|
|
|
n.PubSubRouter = pubsub.NewPubSubRouter(n.Host, n.OracleTopic)
|
2020-10-21 19:54:40 +00:00
|
|
|
// wait for setting up pubsub
|
2020-11-04 17:46:35 +00:00
|
|
|
//time.Sleep(3 * time.Second)
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
func (n *Node) setupConsensusManager(privateKey crypto.PrivKey, minApprovals int) error {
|
|
|
|
pkeyRaw, err := privateKey.Raw()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
n.ConsensusManager = consensus.NewPBFTConsensusManager(n.PubSubRouter, minApprovals, pkeyRaw, n.Ethereum)
|
|
|
|
return nil
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
|
2020-11-04 17:46:35 +00:00
|
|
|
func (n *Node) setupLibp2pHost(ctx context.Context, privateKey crypto.PrivKey, pexDiscoveryUpdateTime time.Duration) {
|
2020-11-04 18:17:01 +00:00
|
|
|
listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", n.Config.ListenAddr, n.Config.ListenPort))
|
2020-10-21 19:54:40 +00:00
|
|
|
if err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Fatal("Failed to generate new node multiaddress:", err)
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
host, err := libp2p.New(
|
|
|
|
ctx,
|
|
|
|
libp2p.ListenAddrs(listenMultiAddr),
|
|
|
|
libp2p.Identity(privateKey),
|
|
|
|
)
|
|
|
|
if err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Fatal("Failed to set a new libp2p node:", err)
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
n.Host = host
|
|
|
|
|
2020-11-04 18:17:01 +00:00
|
|
|
logrus.Info(fmt.Sprintf("[*] Your Multiaddress Is: /ip4/%s/tcp/%d/p2p/%s", n.Config.ListenAddr, n.Config.ListenPort, host.ID().Pretty()))
|
2020-10-21 19:54:40 +00:00
|
|
|
|
2020-11-04 17:46:35 +00:00
|
|
|
var bootstrapMaddrs []multiaddr.Multiaddr
|
|
|
|
for _, a := range n.Config.BootstrapNodes {
|
|
|
|
maddr, err := multiaddr.NewMultiaddr(a)
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
2020-11-04 17:46:35 +00:00
|
|
|
logrus.Fatalf("Invalid multiaddress of bootstrap node: %s", err.Error())
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
2020-11-04 17:46:35 +00:00
|
|
|
bootstrapMaddrs = append(bootstrapMaddrs, maddr)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
2020-11-15 05:59:46 +00:00
|
|
|
if n.Config.IsBootstrap {
|
|
|
|
bootstrapMaddrs = nil
|
|
|
|
}
|
2020-11-04 17:46:35 +00:00
|
|
|
discovery, err := pex.NewPEXDiscovery(host, bootstrapMaddrs, pexDiscoveryUpdateTime)
|
2020-11-13 15:51:23 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal("Can't set up PEX discovery protocol, exiting... ", err)
|
|
|
|
}
|
2020-11-04 17:46:35 +00:00
|
|
|
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Info("Announcing ourselves...")
|
2020-11-04 17:46:35 +00:00
|
|
|
_, err = discovery.Advertise(context.TODO(), n.Config.Rendezvous)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatalf("Failed to announce this node to the network: %s", err.Error())
|
|
|
|
}
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Info("Successfully announced!")
|
2020-10-20 18:18:36 +00:00
|
|
|
|
2020-11-04 17:46:35 +00:00
|
|
|
// Discover unbounded count of peers
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Info("Searching for other peers...")
|
2020-11-04 17:46:35 +00:00
|
|
|
peerChan, err := discovery.FindPeers(context.TODO(), n.Config.Rendezvous)
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Fatal("Failed to find new peers, exiting...", err)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
MainLoop:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
break MainLoop
|
|
|
|
case newPeer := <-peerChan:
|
|
|
|
{
|
2020-10-21 19:54:40 +00:00
|
|
|
if len(newPeer.Addrs) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if newPeer.ID.String() == n.Host.ID().String() {
|
|
|
|
continue
|
|
|
|
}
|
2020-11-04 17:46:35 +00:00
|
|
|
logrus.Infof("Found peer: %s", newPeer)
|
2020-10-20 18:18:36 +00:00
|
|
|
// Connect to the peer
|
|
|
|
if err := n.Host.Connect(ctx, newPeer); err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Warn("Connection failed: ", err)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
2020-11-04 17:46:35 +00:00
|
|
|
logrus.Info("Connected to newly discovered peer: ", newPeer)
|
2020-10-20 18:18:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
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 {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.SetLevel(logrus.DebugLevel)
|
2020-08-19 19:26:48 +00:00
|
|
|
} else {
|
2020-11-15 10:11:07 +00:00
|
|
|
logrus.SetLevel(logrus.DebugLevel)
|
2020-08-19 19:26:48 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
2020-10-21 20:36:05 +00:00
|
|
|
logrus.Panic(err)
|
2020-08-19 19:26:48 +00:00
|
|
|
}
|
2020-08-03 20:01:38 +00:00
|
|
|
|
2020-11-15 10:11:07 +00:00
|
|
|
var privateKey crypto.PrivKey
|
|
|
|
|
|
|
|
if node.Config.IsBootstrap {
|
|
|
|
if _, err := os.Stat(".bootstrap_privkey"); os.IsNotExist(err) {
|
|
|
|
privateKey, err = generatePrivateKey()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
f, _ := os.Create(".bootstrap_privkey")
|
|
|
|
r, _ := privateKey.Raw()
|
|
|
|
f.Write(r)
|
|
|
|
} else {
|
|
|
|
pkey, _ := ioutil.ReadFile(".bootstrap_privkey")
|
|
|
|
privateKey, _ = crypto.UnmarshalEd25519PrivateKey(pkey)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
privateKey, err = generatePrivateKey()
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
|
|
|
node.GlobalCtx = ctx
|
|
|
|
node.GlobalCtxCancel = ctxCancel
|
|
|
|
|
2020-11-15 10:11:07 +00:00
|
|
|
node.setupNode(ctx, privateKey, DefaultPEXUpdateTime)
|
2020-10-21 19:54:40 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
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.
|
2020-11-14 00:32:50 +00:00
|
|
|
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, r)
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return prvKey, nil
|
|
|
|
}
|
2020-10-28 17:35:56 +00:00
|
|
|
|
2020-11-14 00:32:50 +00:00
|
|
|
// TODO generate Miner for the node
|