2020-03-10 12:20:34 -07:00
|
|
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
|
|
|
|
package node
|
|
|
|
|
|
|
|
// #include "salticidae/network.h"
|
|
|
|
// void onTerm(int sig, void *);
|
2020-04-20 17:00:36 -07:00
|
|
|
// void errorHandler(SalticidaeCError *, bool, int32_t, void *);
|
2020-03-10 12:20:34 -07:00
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/pem"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2020-04-16 08:39:20 -07:00
|
|
|
"path"
|
2020-03-10 12:20:34 -07:00
|
|
|
"sync"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"github.com/ava-labs/salticidae-go"
|
|
|
|
|
|
|
|
"github.com/ava-labs/gecko/api"
|
|
|
|
"github.com/ava-labs/gecko/api/admin"
|
|
|
|
"github.com/ava-labs/gecko/api/ipcs"
|
|
|
|
"github.com/ava-labs/gecko/api/keystore"
|
|
|
|
"github.com/ava-labs/gecko/api/metrics"
|
|
|
|
"github.com/ava-labs/gecko/chains"
|
2020-03-19 14:14:27 -07:00
|
|
|
"github.com/ava-labs/gecko/chains/atomic"
|
2020-03-10 12:20:34 -07:00
|
|
|
"github.com/ava-labs/gecko/database"
|
|
|
|
"github.com/ava-labs/gecko/database/prefixdb"
|
|
|
|
"github.com/ava-labs/gecko/genesis"
|
|
|
|
"github.com/ava-labs/gecko/ids"
|
|
|
|
"github.com/ava-labs/gecko/networking"
|
|
|
|
"github.com/ava-labs/gecko/networking/xputtest"
|
|
|
|
"github.com/ava-labs/gecko/snow/triggers"
|
|
|
|
"github.com/ava-labs/gecko/snow/validators"
|
|
|
|
"github.com/ava-labs/gecko/utils/hashing"
|
|
|
|
"github.com/ava-labs/gecko/utils/logging"
|
2020-04-02 20:43:02 -07:00
|
|
|
"github.com/ava-labs/gecko/utils/wrappers"
|
2020-03-10 12:20:34 -07:00
|
|
|
"github.com/ava-labs/gecko/vms"
|
|
|
|
"github.com/ava-labs/gecko/vms/avm"
|
2020-03-30 13:23:06 -07:00
|
|
|
"github.com/ava-labs/gecko/vms/nftfx"
|
2020-03-10 12:20:34 -07:00
|
|
|
"github.com/ava-labs/gecko/vms/platformvm"
|
2020-03-30 14:46:18 -07:00
|
|
|
"github.com/ava-labs/gecko/vms/propertyfx"
|
2020-04-16 08:39:20 -07:00
|
|
|
"github.com/ava-labs/gecko/vms/rpcchainvm"
|
2020-03-10 12:20:34 -07:00
|
|
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
|
|
|
"github.com/ava-labs/gecko/vms/spchainvm"
|
|
|
|
"github.com/ava-labs/gecko/vms/spdagvm"
|
|
|
|
"github.com/ava-labs/gecko/vms/timestampvm"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-03-12 13:53:34 -07:00
|
|
|
maxMessageSize = 1 << 25 // maximum size of a message sent with salticidae
|
2020-03-10 12:20:34 -07:00
|
|
|
)
|
|
|
|
|
2020-03-31 15:56:05 -07:00
|
|
|
var (
|
|
|
|
genesisHashKey = []byte("genesisID")
|
|
|
|
)
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
// MainNode is the reference for node callbacks
|
|
|
|
var MainNode = Node{}
|
|
|
|
|
|
|
|
// Node is an instance of an Ava node.
|
|
|
|
type Node struct {
|
|
|
|
Log logging.Logger
|
|
|
|
LogFactory logging.Factory
|
|
|
|
HTTPLog logging.Logger
|
|
|
|
|
2020-03-12 09:11:45 -07:00
|
|
|
// This node's unique ID used when communicating with other nodes
|
2020-03-10 12:20:34 -07:00
|
|
|
// (in consensus, for example)
|
|
|
|
ID ids.ShortID
|
|
|
|
|
|
|
|
// Storage for this node
|
|
|
|
DB database.Database
|
|
|
|
|
|
|
|
// Handles calls to Keystore API
|
|
|
|
keystoreServer keystore.Keystore
|
|
|
|
|
2020-03-19 14:14:27 -07:00
|
|
|
// Manages shared memory
|
|
|
|
sharedMemory atomic.SharedMemory
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
// Manages creation of blockchains and routing messages to them
|
|
|
|
chainManager chains.Manager
|
|
|
|
|
|
|
|
// Manages Virtual Machines
|
|
|
|
vmManager vms.Manager
|
|
|
|
|
|
|
|
// dispatcher for events as they happen in consensus
|
|
|
|
DecisionDispatcher *triggers.EventDispatcher
|
|
|
|
ConsensusDispatcher *triggers.EventDispatcher
|
|
|
|
|
|
|
|
// Event loop manager
|
|
|
|
EC salticidae.EventContext
|
|
|
|
// Network that manages validator peers
|
|
|
|
PeerNet salticidae.PeerNetwork
|
|
|
|
// Network that manages clients
|
|
|
|
ClientNet salticidae.MsgNetwork // TODO: Remove
|
|
|
|
|
|
|
|
// API that handles new connections
|
|
|
|
ValidatorAPI *networking.Handshake
|
|
|
|
// API that handles voting messages
|
|
|
|
ConsensusAPI *networking.Voting
|
|
|
|
|
|
|
|
// current validators of the network
|
|
|
|
vdrs validators.Manager
|
|
|
|
|
|
|
|
// APIs that handle client messages
|
|
|
|
// TODO: Remove
|
|
|
|
Issuer *xputtest.Issuer
|
|
|
|
CClientAPI *xputtest.CClient
|
|
|
|
|
|
|
|
// Handles HTTP API calls
|
|
|
|
APIServer api.Server
|
|
|
|
|
|
|
|
// This node's configuration
|
|
|
|
Config *Config
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
******************************************************************************
|
|
|
|
*************************** P2P Networking Section ***************************
|
|
|
|
******************************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
//export onTerm
|
|
|
|
func onTerm(C.int, unsafe.Pointer) {
|
|
|
|
MainNode.Log.Debug("Terminate signal received")
|
|
|
|
MainNode.EC.Stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
//export errorHandler
|
2020-04-20 17:00:36 -07:00
|
|
|
func errorHandler(_err *C.struct_SalticidaeCError, fatal C.bool, asyncID C.int32_t, _ unsafe.Pointer) {
|
2020-03-10 12:20:34 -07:00
|
|
|
err := (*salticidae.Error)(unsafe.Pointer(_err))
|
|
|
|
if fatal {
|
|
|
|
MainNode.Log.Fatal("Error during async call: %s", salticidae.StrError(err.GetCode()))
|
|
|
|
MainNode.EC.Stop()
|
|
|
|
return
|
|
|
|
}
|
2020-04-21 11:32:00 -07:00
|
|
|
MainNode.Log.Debug("Error during async with ID %d call: %s", asyncID, salticidae.StrError(err.GetCode()))
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) initNetlib() error {
|
|
|
|
// Create main event context
|
|
|
|
n.EC = salticidae.NewEventContext()
|
|
|
|
|
|
|
|
// Set up interrupt signal and terminate signal handlers
|
|
|
|
evInt := salticidae.NewSigEvent(n.EC, salticidae.SigEventCallback(C.onTerm), nil)
|
|
|
|
evInt.Add(salticidae.SIGINT)
|
|
|
|
evTerm := salticidae.NewSigEvent(n.EC, salticidae.SigEventCallback(C.onTerm), nil)
|
|
|
|
evTerm.Add(salticidae.SIGTERM)
|
|
|
|
|
|
|
|
// Create peer network config, may have tls enabled
|
|
|
|
peerConfig := salticidae.NewPeerNetworkConfig()
|
2020-04-15 13:54:39 -07:00
|
|
|
msgConfig := peerConfig.AsMsgNetworkConfig()
|
|
|
|
msgConfig.MaxMsgSize(maxMessageSize)
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
if n.Config.EnableStaking {
|
|
|
|
msgConfig.EnableTLS(true)
|
|
|
|
msgConfig.TLSKeyFile(n.Config.StakingKeyFile)
|
|
|
|
msgConfig.TLSCertFile(n.Config.StakingCertFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the peer network
|
|
|
|
err := salticidae.NewError()
|
|
|
|
n.PeerNet = salticidae.NewPeerNetwork(n.EC, peerConfig, &err)
|
|
|
|
if code := err.GetCode(); code != 0 {
|
|
|
|
return errors.New(salticidae.StrError(code))
|
|
|
|
}
|
|
|
|
// Add peer network error handling
|
|
|
|
net := n.PeerNet.AsMsgNetwork()
|
|
|
|
net.RegErrorHandler(salticidae.MsgNetworkErrorCallback(C.errorHandler), nil)
|
|
|
|
|
|
|
|
if n.Config.ThroughputServerEnabled {
|
|
|
|
// Create the client network
|
|
|
|
msgConfig := salticidae.NewMsgNetworkConfig()
|
2020-03-12 09:11:45 -07:00
|
|
|
msgConfig.MaxMsgSize(maxMessageSize)
|
2020-03-10 12:20:34 -07:00
|
|
|
n.ClientNet = salticidae.NewMsgNetwork(n.EC, msgConfig, &err)
|
|
|
|
if code := err.GetCode(); code != 0 {
|
|
|
|
return errors.New(salticidae.StrError(code))
|
|
|
|
}
|
|
|
|
// Add client network error handling
|
|
|
|
n.ClientNet.RegErrorHandler(salticidae.MsgNetworkErrorCallback(C.errorHandler), nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) initValidatorNet() error {
|
|
|
|
// Initialize validator manager and default subnet's validator set
|
|
|
|
defaultSubnetValidators := validators.NewSet()
|
|
|
|
if !n.Config.EnableStaking {
|
|
|
|
defaultSubnetValidators.Add(validators.NewValidator(n.ID, 1))
|
|
|
|
}
|
|
|
|
n.vdrs = validators.NewManager()
|
|
|
|
n.vdrs.PutValidatorSet(platformvm.DefaultSubnetID, defaultSubnetValidators)
|
|
|
|
|
|
|
|
cErr := salticidae.NewError()
|
|
|
|
serverIP := salticidae.NewNetAddrFromIPPortString(n.Config.StakingIP.String(), true, &cErr)
|
|
|
|
if code := cErr.GetCode(); code != 0 {
|
|
|
|
return errors.New(salticidae.StrError(code))
|
|
|
|
}
|
|
|
|
|
|
|
|
n.ValidatorAPI = &networking.HandshakeNet
|
|
|
|
n.ValidatorAPI.Initialize(
|
|
|
|
/*log=*/ n.Log,
|
|
|
|
/*validators=*/ defaultSubnetValidators,
|
|
|
|
/*myIP=*/ serverIP,
|
|
|
|
/*myID=*/ n.ID,
|
|
|
|
/*network=*/ n.PeerNet,
|
|
|
|
/*metrics=*/ n.Config.ConsensusParams.Metrics,
|
|
|
|
/*enableStaking=*/ n.Config.EnableStaking,
|
|
|
|
/*networkID=*/ n.Config.NetworkID,
|
|
|
|
)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) initConsensusNet() {
|
|
|
|
vdrs, ok := n.vdrs.GetValidatorSet(platformvm.DefaultSubnetID)
|
|
|
|
n.Log.AssertTrue(ok, "should have initialize the validator set already")
|
|
|
|
|
|
|
|
n.ConsensusAPI = &networking.VotingNet
|
|
|
|
n.ConsensusAPI.Initialize(n.Log, vdrs, n.PeerNet, n.ValidatorAPI.Connections(), n.chainManager.Router(), n.Config.ConsensusParams.Metrics)
|
|
|
|
|
|
|
|
n.Log.AssertNoError(n.ConsensusDispatcher.Register("gossip", n.ConsensusAPI))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) initClients() {
|
|
|
|
n.Issuer = &xputtest.Issuer{}
|
2020-03-13 14:31:23 -07:00
|
|
|
n.Issuer.Initialize(n.Log)
|
2020-03-10 12:20:34 -07:00
|
|
|
|
|
|
|
n.CClientAPI = &xputtest.CClientHandler
|
|
|
|
n.CClientAPI.Initialize(n.ClientNet, n.Issuer)
|
|
|
|
|
|
|
|
n.chainManager.AddRegistrant(n.Issuer)
|
|
|
|
}
|
|
|
|
|
|
|
|
// StartConsensusServer starts the P2P server this node uses to communicate
|
|
|
|
// with other nodes
|
|
|
|
func (n *Node) StartConsensusServer() error {
|
|
|
|
n.Log.Verbo("starting the consensus server")
|
|
|
|
|
|
|
|
n.PeerNet.AsMsgNetwork().Start()
|
|
|
|
|
|
|
|
err := salticidae.NewError()
|
|
|
|
|
|
|
|
// The IP this node listens on for P2P messaging
|
|
|
|
serverIP := salticidae.NewNetAddrFromIPPortString(n.Config.StakingIP.String(), true, &err)
|
|
|
|
if code := err.GetCode(); code != 0 {
|
|
|
|
return fmt.Errorf("failed to create ip addr: %s", salticidae.StrError(code))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Listen for P2P messages
|
|
|
|
n.PeerNet.Listen(serverIP, &err)
|
|
|
|
if code := err.GetCode(); code != 0 {
|
2020-04-22 09:46:54 -07:00
|
|
|
return fmt.Errorf("failed to listen on consensus server at %s: %s", n.Config.StakingIP, salticidae.StrError(code))
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start a server to handle throughput tests if configuration says to. Disabled by default.
|
|
|
|
if n.Config.ThroughputServerEnabled {
|
|
|
|
n.ClientNet.Start()
|
|
|
|
|
|
|
|
clientIP := salticidae.NewNetAddrFromIPPortString(fmt.Sprintf("127.0.0.1:%d", n.Config.ThroughputPort), true, &err)
|
|
|
|
if code := err.GetCode(); code != 0 {
|
|
|
|
return fmt.Errorf("failed to start xput server: %s", salticidae.StrError(code))
|
|
|
|
}
|
|
|
|
|
|
|
|
n.ClientNet.Listen(clientIP, &err)
|
|
|
|
if code := err.GetCode(); code != 0 {
|
2020-04-22 09:46:54 -07:00
|
|
|
return fmt.Errorf("failed to listen on xput server at 127.0.0.1:%d: %s", n.Config.ThroughputPort, salticidae.StrError(code))
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add bootstrap nodes to the peer network
|
|
|
|
for _, peer := range n.Config.BootstrapPeers {
|
|
|
|
if !peer.IP.Equal(n.Config.StakingIP) {
|
2020-04-18 19:47:53 -07:00
|
|
|
bootstrapAddr := salticidae.NewNetAddrFromIPPortString(peer.IP.String(), true, &err)
|
2020-04-18 18:02:40 -07:00
|
|
|
if code := err.GetCode(); code != 0 {
|
|
|
|
return fmt.Errorf("failed to create bootstrap ip addr: %s", salticidae.StrError(code))
|
|
|
|
}
|
2020-04-18 19:47:53 -07:00
|
|
|
|
|
|
|
n.ValidatorAPI.Connect(bootstrapAddr)
|
2020-03-10 12:20:34 -07:00
|
|
|
} else {
|
|
|
|
n.Log.Error("can't add self as a bootstrapper")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dispatch starts the node's servers.
|
|
|
|
// Returns when the node exits.
|
|
|
|
func (n *Node) Dispatch() { n.EC.Dispatch() }
|
|
|
|
|
|
|
|
/*
|
|
|
|
******************************************************************************
|
|
|
|
*********************** End P2P Networking Section ***************************
|
|
|
|
******************************************************************************
|
|
|
|
*/
|
|
|
|
|
2020-03-31 15:56:05 -07:00
|
|
|
func (n *Node) initDatabase() error {
|
|
|
|
n.DB = n.Config.DB
|
|
|
|
|
|
|
|
expectedGenesis, err := genesis.Genesis(n.Config.NetworkID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
rawExpectedGenesisHash := hashing.ComputeHash256(expectedGenesis)
|
|
|
|
|
|
|
|
rawGenesisHash, err := n.DB.Get(genesisHashKey)
|
|
|
|
if err == database.ErrNotFound {
|
|
|
|
rawGenesisHash = rawExpectedGenesisHash
|
|
|
|
err = n.DB.Put(genesisHashKey, rawGenesisHash)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
genesisHash, err := ids.ToID(rawGenesisHash)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
expectedGenesisHash, err := ids.ToID(rawExpectedGenesisHash)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !genesisHash.Equals(expectedGenesisHash) {
|
|
|
|
return fmt.Errorf("db contains invalid genesis hash. DB Genesis: %s Generated Genesis: %s", genesisHash, expectedGenesisHash)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
|
|
|
|
// Initialize this node's ID
|
|
|
|
// If staking is disabled, a node's ID is a hash of its IP
|
|
|
|
// Otherwise, it is a hash of the TLS certificate that this node
|
|
|
|
// uses for P2P communication
|
|
|
|
func (n *Node) initNodeID() error {
|
|
|
|
if !n.Config.EnableStaking {
|
|
|
|
n.ID = ids.NewShortID(hashing.ComputeHash160Array([]byte(n.Config.StakingIP.String())))
|
|
|
|
n.Log.Info("Set the node's ID to %s", n.ID)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
stakeCert, err := ioutil.ReadFile(n.Config.StakingCertFile)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("problem reading staking certificate: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
block, _ := pem.Decode(stakeCert)
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("problem parsing staking certificate: %w", err)
|
|
|
|
}
|
|
|
|
n.ID, err = ids.ToShortID(hashing.PubkeyBytesToAddress(cert.Raw))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("problem deriving staker ID from certificate: %w", err)
|
|
|
|
}
|
|
|
|
n.Log.Info("Set node's ID to %s", n.ID)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the vmManager and register the following vms:
|
2020-04-16 08:39:20 -07:00
|
|
|
// AVM, Simple Payments DAG, Simple Payments Chain
|
2020-03-10 12:20:34 -07:00
|
|
|
// The Platform VM is registered in initStaking because
|
|
|
|
// its factory needs to reference n.chainManager, which is nil right now
|
2020-04-02 20:43:02 -07:00
|
|
|
func (n *Node) initVMManager() error {
|
|
|
|
avaAssetID, err := genesis.AVAAssetID(n.Config.NetworkID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
n.vmManager = vms.NewManager(&n.APIServer, n.HTTPLog)
|
2020-04-02 20:43:02 -07:00
|
|
|
|
|
|
|
errs := wrappers.Errs{}
|
|
|
|
errs.Add(
|
|
|
|
n.vmManager.RegisterVMFactory(avm.ID, &avm.Factory{
|
|
|
|
AVA: avaAssetID,
|
|
|
|
Platform: ids.Empty,
|
|
|
|
}),
|
2020-04-16 08:39:20 -07:00
|
|
|
n.vmManager.RegisterVMFactory(genesis.EVMID, &rpcchainvm.Factory{Path: path.Join(n.Config.PluginDir, "evm")}),
|
2020-04-02 20:43:02 -07:00
|
|
|
n.vmManager.RegisterVMFactory(spdagvm.ID, &spdagvm.Factory{TxFee: n.Config.AvaTxFee}),
|
|
|
|
n.vmManager.RegisterVMFactory(spchainvm.ID, &spchainvm.Factory{}),
|
|
|
|
n.vmManager.RegisterVMFactory(timestampvm.ID, ×tampvm.Factory{}),
|
|
|
|
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{}),
|
|
|
|
n.vmManager.RegisterVMFactory(nftfx.ID, &nftfx.Factory{}),
|
|
|
|
n.vmManager.RegisterVMFactory(propertyfx.ID, &propertyfx.Factory{}),
|
|
|
|
)
|
|
|
|
return errs.Err
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the EventDispatcher used for hooking events
|
|
|
|
// into the general process flow.
|
|
|
|
func (n *Node) initEventDispatcher() {
|
|
|
|
n.DecisionDispatcher = &triggers.EventDispatcher{}
|
|
|
|
n.DecisionDispatcher.Initialize(n.Log)
|
|
|
|
|
|
|
|
n.ConsensusDispatcher = &triggers.EventDispatcher{}
|
|
|
|
n.ConsensusDispatcher.Initialize(n.Log)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initializes the Platform chain.
|
|
|
|
// Its genesis data specifies the other chains that should
|
|
|
|
// be created.
|
2020-04-02 20:43:02 -07:00
|
|
|
func (n *Node) initChains() error {
|
2020-03-10 12:20:34 -07:00
|
|
|
n.Log.Info("initializing chains")
|
|
|
|
|
|
|
|
vdrs := n.vdrs
|
2020-03-16 14:21:38 -07:00
|
|
|
|
|
|
|
// If staking is disabled, ignore updates to Subnets' validator sets
|
|
|
|
// Instead of updating node's validator manager, platform chain makes changes
|
|
|
|
// to its own local validator manager (which isn't used for sampling)
|
2020-03-10 12:20:34 -07:00
|
|
|
if !n.Config.EnableStaking {
|
|
|
|
defaultSubnetValidators := validators.NewSet()
|
2020-03-16 14:21:38 -07:00
|
|
|
defaultSubnetValidators.Add(validators.NewValidator(n.ID, 1))
|
2020-03-10 12:20:34 -07:00
|
|
|
vdrs = validators.NewManager()
|
|
|
|
vdrs.PutValidatorSet(platformvm.DefaultSubnetID, defaultSubnetValidators)
|
|
|
|
}
|
|
|
|
|
2020-04-02 20:43:02 -07:00
|
|
|
avaAssetID, err := genesis.AVAAssetID(n.Config.NetworkID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
createAVMTx, err := genesis.VMGenesis(n.Config.NetworkID, avm.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = n.vmManager.RegisterVMFactory(
|
2020-03-10 12:20:34 -07:00
|
|
|
/*vmID=*/ platformvm.ID,
|
|
|
|
/*vmFactory=*/ &platformvm.Factory{
|
2020-03-19 14:59:12 -07:00
|
|
|
ChainManager: n.chainManager,
|
|
|
|
Validators: vdrs,
|
|
|
|
StakingEnabled: n.Config.EnableStaking,
|
2020-04-02 20:43:02 -07:00
|
|
|
AVA: avaAssetID,
|
|
|
|
AVM: createAVMTx.ID(),
|
2020-03-10 12:20:34 -07:00
|
|
|
},
|
|
|
|
)
|
2020-04-02 20:43:02 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
|
|
|
|
beacons := validators.NewSet()
|
|
|
|
for _, peer := range n.Config.BootstrapPeers {
|
|
|
|
beacons.Add(validators.NewValidator(peer.ID, 1))
|
|
|
|
}
|
|
|
|
|
2020-04-02 20:43:02 -07:00
|
|
|
genesisBytes, err := genesis.Genesis(n.Config.NetworkID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
|
|
|
|
// Create the Platform Chain
|
|
|
|
n.chainManager.ForceCreateChain(chains.ChainParameters{
|
|
|
|
ID: ids.Empty,
|
2020-03-16 14:21:38 -07:00
|
|
|
SubnetID: platformvm.DefaultSubnetID,
|
2020-03-10 12:20:34 -07:00
|
|
|
GenesisData: genesisBytes, // Specifies other chains to create
|
|
|
|
VMAlias: platformvm.ID.String(),
|
|
|
|
CustomBeacons: beacons,
|
|
|
|
})
|
2020-04-02 20:43:02 -07:00
|
|
|
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// initAPIServer initializes the server that handles HTTP calls
|
|
|
|
func (n *Node) initAPIServer() {
|
|
|
|
n.Log.Info("Initializing API server")
|
|
|
|
|
|
|
|
n.APIServer.Initialize(n.Log, n.LogFactory, n.Config.HTTPPort)
|
|
|
|
|
|
|
|
if n.Config.EnableHTTPS {
|
|
|
|
n.Log.Debug("Initializing API server with TLS Enabled")
|
|
|
|
go n.Log.RecoverAndPanic(func() {
|
|
|
|
if err := n.APIServer.DispatchTLS(n.Config.HTTPSCertFile, n.Config.HTTPSKeyFile); err != nil {
|
|
|
|
n.Log.Warn("API server initialization failed with %s, attempting to create insecure API server", err)
|
|
|
|
n.APIServer.Dispatch()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
n.Log.Debug("Initializing API server with TLS Disabled")
|
|
|
|
go n.Log.RecoverAndPanic(func() { n.APIServer.Dispatch() })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assumes n.DB, n.vdrs all initialized (non-nil)
|
|
|
|
func (n *Node) initChainManager() {
|
|
|
|
n.chainManager = chains.New(
|
2020-03-16 14:21:38 -07:00
|
|
|
n.Config.EnableStaking,
|
2020-03-10 12:20:34 -07:00
|
|
|
n.Log,
|
|
|
|
n.LogFactory,
|
|
|
|
n.vmManager,
|
|
|
|
n.DecisionDispatcher,
|
|
|
|
n.ConsensusDispatcher,
|
|
|
|
n.DB,
|
|
|
|
n.Config.ConsensusRouter,
|
|
|
|
&networking.VotingNet,
|
|
|
|
n.Config.ConsensusParams,
|
|
|
|
n.vdrs,
|
|
|
|
n.ID,
|
|
|
|
n.Config.NetworkID,
|
|
|
|
n.ValidatorAPI,
|
|
|
|
&n.APIServer,
|
|
|
|
&n.keystoreServer,
|
2020-03-19 14:14:27 -07:00
|
|
|
&n.sharedMemory,
|
2020-03-10 12:20:34 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
n.chainManager.AddRegistrant(&n.APIServer)
|
|
|
|
}
|
|
|
|
|
2020-03-19 14:14:27 -07:00
|
|
|
// initSharedMemory initializes the shared memory for cross chain interation
|
|
|
|
func (n *Node) initSharedMemory() {
|
|
|
|
n.Log.Info("initializing SharedMemory")
|
|
|
|
sharedMemoryDB := prefixdb.New([]byte("shared memory"), n.DB)
|
|
|
|
n.sharedMemory.Initialize(n.Log, sharedMemoryDB)
|
|
|
|
}
|
|
|
|
|
|
|
|
// initKeystoreAPI initializes the keystore service
|
2020-03-10 12:20:34 -07:00
|
|
|
// Assumes n.APIServer is already set
|
|
|
|
func (n *Node) initKeystoreAPI() {
|
|
|
|
n.Log.Info("initializing Keystore API")
|
|
|
|
keystoreDB := prefixdb.New([]byte("keystore"), n.DB)
|
|
|
|
n.keystoreServer.Initialize(n.Log, keystoreDB)
|
|
|
|
keystoreHandler := n.keystoreServer.CreateHandler()
|
|
|
|
if n.Config.KeystoreAPIEnabled {
|
|
|
|
n.APIServer.AddRoute(keystoreHandler, &sync.RWMutex{}, "keystore", "", n.HTTPLog)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// initMetricsAPI initializes the Metrics API
|
|
|
|
// Assumes n.APIServer is already set
|
|
|
|
func (n *Node) initMetricsAPI() {
|
|
|
|
n.Log.Info("initializing Metrics API")
|
|
|
|
registry, handler := metrics.NewService()
|
|
|
|
if n.Config.MetricsAPIEnabled {
|
|
|
|
n.APIServer.AddRoute(handler, &sync.RWMutex{}, "metrics", "", n.HTTPLog)
|
|
|
|
}
|
|
|
|
n.Config.ConsensusParams.Metrics = registry
|
|
|
|
}
|
|
|
|
|
|
|
|
// initAdminAPI initializes the Admin API service
|
|
|
|
// Assumes n.log, n.chainManager, and n.ValidatorAPI already initialized
|
|
|
|
func (n *Node) initAdminAPI() {
|
|
|
|
if n.Config.AdminAPIEnabled {
|
|
|
|
n.Log.Info("initializing Admin API")
|
2020-03-12 09:30:05 -07:00
|
|
|
service := admin.NewService(n.ID, n.Config.NetworkID, n.Log, n.chainManager, n.ValidatorAPI.Connections(), &n.APIServer)
|
2020-03-10 12:20:34 -07:00
|
|
|
n.APIServer.AddRoute(service, &sync.RWMutex{}, "admin", "", n.HTTPLog)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// initIPCAPI initializes the IPC API service
|
|
|
|
// Assumes n.log and n.chainManager already initialized
|
|
|
|
func (n *Node) initIPCAPI() {
|
|
|
|
if n.Config.IPCEnabled {
|
|
|
|
n.Log.Info("initializing IPC API")
|
|
|
|
service := ipcs.NewService(n.Log, n.chainManager, n.DecisionDispatcher, &n.APIServer)
|
|
|
|
n.APIServer.AddRoute(service, &sync.RWMutex{}, "ipcs", "", n.HTTPLog)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Give chains and VMs aliases as specified by the genesis information
|
2020-04-02 20:43:02 -07:00
|
|
|
func (n *Node) initAliases() error {
|
2020-03-10 12:20:34 -07:00
|
|
|
n.Log.Info("initializing aliases")
|
2020-04-02 20:43:02 -07:00
|
|
|
defaultAliases, chainAliases, vmAliases, err := genesis.Aliases(n.Config.NetworkID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
for chainIDKey, aliases := range chainAliases {
|
|
|
|
chainID := ids.NewID(chainIDKey)
|
|
|
|
for _, alias := range aliases {
|
2020-04-02 20:43:02 -07:00
|
|
|
if err := n.chainManager.Alias(chainID, alias); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for vmIDKey, aliases := range vmAliases {
|
|
|
|
vmID := ids.NewID(vmIDKey)
|
|
|
|
for _, alias := range aliases {
|
2020-04-02 20:43:02 -07:00
|
|
|
if err := n.vmManager.Alias(vmID, alias); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for url, aliases := range defaultAliases {
|
2020-04-02 20:43:02 -07:00
|
|
|
if err := n.APIServer.AddAliases(url, aliases...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-04-02 20:43:02 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize this node
|
|
|
|
func (n *Node) Initialize(Config *Config, logger logging.Logger, logFactory logging.Factory) error {
|
|
|
|
n.Log = logger
|
|
|
|
n.LogFactory = logFactory
|
|
|
|
n.Config = Config
|
|
|
|
|
|
|
|
httpLog, err := logFactory.MakeSubdir("http")
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("problem initializing HTTP logger: %w", err)
|
|
|
|
}
|
|
|
|
n.HTTPLog = httpLog
|
|
|
|
|
2020-03-31 15:56:05 -07:00
|
|
|
if err := n.initDatabase(); err != nil { // Set up the node's database
|
|
|
|
return fmt.Errorf("problem initializing database: %w", err)
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
|
|
|
|
if err = n.initNodeID(); err != nil { // Derive this node's ID
|
|
|
|
return fmt.Errorf("problem initializing staker ID: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-03-19 14:14:27 -07:00
|
|
|
// initialize shared memory
|
|
|
|
n.initSharedMemory()
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
// Start HTTP APIs
|
|
|
|
n.initAPIServer() // Start the API Server
|
|
|
|
n.initKeystoreAPI() // Start the Keystore API
|
|
|
|
n.initMetricsAPI() // Start the Metrics API
|
|
|
|
|
|
|
|
// Start node-to-node consensus server
|
|
|
|
if err = n.initNetlib(); err != nil { // Set up all networking
|
|
|
|
return fmt.Errorf("problem initializing networking: %w", err)
|
|
|
|
}
|
2020-04-02 20:43:02 -07:00
|
|
|
if err := n.initValidatorNet(); err != nil { // Set up the validator handshake + authentication
|
|
|
|
return fmt.Errorf("problem initializing validator network: %w", err)
|
|
|
|
}
|
|
|
|
if err := n.initVMManager(); err != nil { // Set up the vm manager
|
|
|
|
return fmt.Errorf("problem initializing the VM manager: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-03-10 12:20:34 -07:00
|
|
|
n.initEventDispatcher() // Set up the event dipatcher
|
|
|
|
n.initChainManager() // Set up the chain manager
|
|
|
|
n.initConsensusNet() // Set up the main consensus network
|
|
|
|
|
|
|
|
// TODO: Remove once API is fully featured for throughput tests
|
|
|
|
if n.Config.ThroughputServerEnabled {
|
|
|
|
n.initClients() // Set up the client servers
|
|
|
|
}
|
|
|
|
|
|
|
|
n.initAdminAPI() // Start the Admin API
|
|
|
|
n.initIPCAPI() // Start the IPC API
|
|
|
|
|
2020-04-02 20:43:02 -07:00
|
|
|
if err := n.initAliases(); err != nil { // Set up aliases
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return n.initChains() // Start the Platform chain
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown this node
|
|
|
|
func (n *Node) Shutdown() {
|
|
|
|
n.Log.Info("shutting down the node")
|
|
|
|
n.ValidatorAPI.Shutdown()
|
|
|
|
n.ConsensusAPI.Shutdown()
|
|
|
|
n.chainManager.Shutdown()
|
|
|
|
}
|