gitlab.com/jokerrs1/Sia@v1.3.2/node/node.go (about)

     1  // Package node provides tooling for creating a Sia node. Sia nodes consist of a
     2  // collection of modules. The node package gives you tools to easily assemble
     3  // various combinations of modules with varying dependencies and settings,
     4  // including templates for assembling sane no-hassle Sia nodes.
     5  package node
     6  
     7  // TODO: Add support for the explorer.
     8  
     9  // TODO: Add support for custom dependencies and parameters for all of the
    10  // modules.
    11  
    12  import (
    13  	"path/filepath"
    14  
    15  	"github.com/NebulousLabs/Sia/modules"
    16  	"github.com/NebulousLabs/Sia/modules/consensus"
    17  	"github.com/NebulousLabs/Sia/modules/gateway"
    18  	"github.com/NebulousLabs/Sia/modules/host"
    19  	"github.com/NebulousLabs/Sia/modules/miner"
    20  	"github.com/NebulousLabs/Sia/modules/renter"
    21  	"github.com/NebulousLabs/Sia/modules/transactionpool"
    22  	"github.com/NebulousLabs/Sia/modules/wallet"
    23  
    24  	"github.com/NebulousLabs/errors"
    25  )
    26  
    27  // NodeParams contains a bunch of parameters for creating a new test node. As
    28  // there are many options, templates are provided that you can modify which
    29  // cover the most common use cases.
    30  //
    31  // Each module is created separately. There are several ways to create a module,
    32  // though not all methods are currently available for each module. You should
    33  // only use one method for creating a module, using multiple methods will cause
    34  // an error.
    35  //		+ Indicate with the 'CreateModule' bool that a module should be created
    36  //		  automatically. To create the module with custom dependencies, pass the
    37  //		  custom dependencies in using the 'ModuleDependencies' field.
    38  //		+ Pass an existing module in directly.
    39  //		+ Set 'CreateModule' to false and do not pass in an existing module.
    40  //		  This will result in a 'nil' module, meaning the node will not have
    41  //		  that module.
    42  type NodeParams struct {
    43  	// Flags to indicate which modules should be created automatically by the
    44  	// server. If you are providing a pre-existing module, do not set the flag
    45  	// for that module.
    46  	//
    47  	// NOTE / TODO: The code does not currently enforce this, but you should not
    48  	// provide a custom module unless all of its dependencies are also custom.
    49  	// Example: if the ConsensusSet is custom, the Gateway should also be
    50  	// custom. The TransactionPool however does not need to be custom in this
    51  	// example.
    52  	CreateConsensusSet    bool
    53  	CreateExplorer        bool
    54  	CreateGateway         bool
    55  	CreateHost            bool
    56  	CreateMiner           bool
    57  	CreateRenter          bool
    58  	CreateTransactionPool bool
    59  	CreateWallet          bool
    60  
    61  	// Custom modules - if the modules is provided directly, the provided
    62  	// module will be used instead of creating a new one. If a custom module is
    63  	// provided, the 'omit' flag for that module must be set to false (which is
    64  	// the default setting).
    65  	ConsensusSet    modules.ConsensusSet
    66  	Explorer        modules.Explorer
    67  	Gateway         modules.Gateway
    68  	Host            modules.Host
    69  	Miner           modules.TestMiner
    70  	Renter          modules.Renter
    71  	TransactionPool modules.TransactionPool
    72  	Wallet          modules.Wallet
    73  
    74  	// The high level directory where all the persistence gets stored for the
    75  	// moudles.
    76  	Dir string
    77  }
    78  
    79  // Node is a collection of Sia modules operating together as a Sia node.
    80  type Node struct {
    81  	// The modules of the node. Modules that are not initialized will be nil.
    82  	ConsensusSet    modules.ConsensusSet
    83  	Explorer        modules.Explorer
    84  	Gateway         modules.Gateway
    85  	Host            modules.Host
    86  	Miner           modules.TestMiner
    87  	Renter          modules.Renter
    88  	TransactionPool modules.TransactionPool
    89  	Wallet          modules.Wallet
    90  
    91  	// The high level directory where all the persistence gets stored for the
    92  	// moudles.
    93  	Dir string
    94  }
    95  
    96  // Close will call close on every module within the node, combining and
    97  // returning the errors.
    98  func (n *Node) Close() (err error) {
    99  	if n.Explorer != nil {
   100  		err = errors.Compose(n.Explorer.Close())
   101  	}
   102  	if n.Miner != nil {
   103  		err = errors.Compose(n.Miner.Close())
   104  	}
   105  	if n.Host != nil {
   106  		err = errors.Compose(n.Host.Close())
   107  	}
   108  	if n.Renter != nil {
   109  		err = errors.Compose(n.Renter.Close())
   110  	}
   111  	if n.Wallet != nil {
   112  		err = errors.Compose(n.Wallet.Close())
   113  	}
   114  	if n.TransactionPool != nil {
   115  		err = errors.Compose(n.TransactionPool.Close())
   116  	}
   117  	if n.ConsensusSet != nil {
   118  		err = errors.Compose(n.ConsensusSet.Close())
   119  	}
   120  	if n.Gateway != nil {
   121  		err = errors.Compose(n.Gateway.Close())
   122  	}
   123  	return err
   124  }
   125  
   126  // New will create a new test node. The inputs to the function are the
   127  // respective 'New' calls for each module. We need to use this awkward method
   128  // of initialization because the siatest package cannot import any of the
   129  // modules directly (so that the modules may use the siatest package to test
   130  // themselves).
   131  func New(params NodeParams) (*Node, error) {
   132  	dir := params.Dir
   133  
   134  	// Gateway.
   135  	g, err := func() (modules.Gateway, error) {
   136  		if params.CreateGateway && params.Gateway != nil {
   137  			return nil, errors.New("cannot both create a gateway and use a passed in gateway")
   138  		}
   139  		/* Template for dealing with optional dependencies:
   140  		if !params.CreateGateway && parames.GatewayDependencies != nil {
   141  			return nil, errors.New("cannot pass in gateway dependencies if you are not creating a gateway")
   142  		}
   143  		*/
   144  		if params.Gateway != nil {
   145  			return params.Gateway, nil
   146  		}
   147  		if !params.CreateGateway {
   148  			return nil, nil
   149  		}
   150  		/* Template for dealing with optional dependencies:
   151  		if params.GatewayDependencies == nil {
   152  			gateway.New(...
   153  		} else {
   154  			gateway.NewDeps(...
   155  		}
   156  		*/
   157  		return gateway.New("localhost:0", false, filepath.Join(dir, modules.GatewayDir))
   158  	}()
   159  	if err != nil {
   160  		return nil, errors.Extend(err, errors.New("unable to create gateway"))
   161  	}
   162  
   163  	// Consensus.
   164  	cs, err := func() (modules.ConsensusSet, error) {
   165  		if params.CreateConsensusSet && params.ConsensusSet != nil {
   166  			return nil, errors.New("cannot both create consensus and use passed in consensus")
   167  		}
   168  		if params.ConsensusSet != nil {
   169  			return params.ConsensusSet, nil
   170  		}
   171  		if !params.CreateConsensusSet {
   172  			return nil, nil
   173  		}
   174  		return consensus.New(g, false, filepath.Join(dir, modules.ConsensusDir))
   175  	}()
   176  	if err != nil {
   177  		return nil, errors.Extend(err, errors.New("unable to create consensus set"))
   178  	}
   179  
   180  	// Transaction Pool.
   181  	tp, err := func() (modules.TransactionPool, error) {
   182  		if params.CreateTransactionPool && params.TransactionPool != nil {
   183  			return nil, errors.New("cannot create transaction pool and also use custom transaction pool")
   184  		}
   185  		if params.TransactionPool != nil {
   186  			return params.TransactionPool, nil
   187  		}
   188  		if !params.CreateTransactionPool {
   189  			return nil, nil
   190  		}
   191  		return transactionpool.New(cs, g, filepath.Join(dir, modules.TransactionPoolDir))
   192  	}()
   193  	if err != nil {
   194  		return nil, errors.Extend(err, errors.New("unable to create transaction pool"))
   195  	}
   196  
   197  	// Wallet.
   198  	w, err := func() (modules.Wallet, error) {
   199  		if params.CreateWallet && params.Wallet != nil {
   200  			return nil, errors.New("cannot create wallet and use custom wallet")
   201  		}
   202  		if params.Wallet != nil {
   203  			return params.Wallet, nil
   204  		}
   205  		if !params.CreateWallet {
   206  			return nil, nil
   207  		}
   208  		return wallet.New(cs, tp, filepath.Join(dir, modules.WalletDir))
   209  	}()
   210  	if err != nil {
   211  		return nil, errors.Extend(err, errors.New("unable to create wallet"))
   212  	}
   213  
   214  	// Host.
   215  	h, err := func() (modules.Host, error) {
   216  		if params.CreateHost && params.Host != nil {
   217  			return nil, errors.New("cannot create host and use custom host")
   218  		}
   219  		if params.Host != nil {
   220  			return params.Host, nil
   221  		}
   222  		if !params.CreateHost {
   223  			return nil, nil
   224  		}
   225  		return host.New(cs, tp, w, "localhost:0", filepath.Join(dir, modules.HostDir))
   226  	}()
   227  	if err != nil {
   228  		return nil, errors.Extend(err, errors.New("unable to create host"))
   229  	}
   230  
   231  	// Renter.
   232  	r, err := func() (modules.Renter, error) {
   233  		if params.CreateRenter && params.Renter != nil {
   234  			return nil, errors.New("cannot create renter and also use custom renter")
   235  		}
   236  		if params.Renter != nil {
   237  			return params.Renter, nil
   238  		}
   239  		if !params.CreateRenter {
   240  			return nil, nil
   241  		}
   242  		return renter.New(g, cs, w, tp, filepath.Join(dir, modules.RenterDir))
   243  	}()
   244  	if err != nil {
   245  		return nil, errors.Extend(err, errors.New("unable to create renter"))
   246  	}
   247  
   248  	// Miner.
   249  	m, err := func() (modules.TestMiner, error) {
   250  		if params.CreateMiner && params.Miner != nil {
   251  			return nil, errors.New("cannot create miner and also use custom miner")
   252  		}
   253  		if params.Miner != nil {
   254  			return params.Miner, nil
   255  		}
   256  		if !params.CreateMiner {
   257  			return nil, nil
   258  		}
   259  		m, err := miner.New(cs, tp, w, filepath.Join(dir, modules.MinerDir))
   260  		if err != nil {
   261  			return nil, err
   262  		}
   263  		return m, nil
   264  	}()
   265  	if err != nil {
   266  		return nil, errors.Extend(err, errors.New("unable to create miner"))
   267  	}
   268  
   269  	// Explorer.
   270  	e, err := func() (modules.Explorer, error) {
   271  		if !params.CreateExplorer && params.Explorer != nil {
   272  			return nil, errors.New("cannot create explorer and also use custom explorer")
   273  		}
   274  		if params.Explorer != nil {
   275  			return params.Explorer, nil
   276  		}
   277  		if !params.CreateExplorer {
   278  			return nil, nil
   279  		}
   280  		// TODO: Implement explorer.
   281  		return nil, errors.New("explorer not implemented")
   282  	}()
   283  	if err != nil {
   284  		return nil, errors.Extend(err, errors.New("unable to create explorer"))
   285  	}
   286  
   287  	return &Node{
   288  		ConsensusSet:    cs,
   289  		Explorer:        e,
   290  		Gateway:         g,
   291  		Host:            h,
   292  		Miner:           m,
   293  		Renter:          r,
   294  		TransactionPool: tp,
   295  		Wallet:          w,
   296  
   297  		Dir: dir,
   298  	}, nil
   299  }