// New creates a transaction pool that is ready to receive transactions. func New(cs modules.ConsensusSet, g modules.Gateway) (*TransactionPool, error) { // Check that the input modules are non-nil. if cs == nil { return nil, errNilCS } if g == nil { return nil, errNilGateway } // Initialize a transaction pool. tp := &TransactionPool{ consensusSet: cs, gateway: g, knownObjects: make(map[ObjectID]TransactionSetID), transactionSets: make(map[TransactionSetID][]types.Transaction), transactionSetDiffs: make(map[TransactionSetID]modules.ConsensusChange), // The consensus change index is intialized to '-1', which indicates // that no consensus changes have been sent yet. The first consensus // change will then have an index of '0'. consensusChangeIndex: -1, mu: sync.New(modules.SafeMutexDelay, 5), } // Register RPCs g.RegisterRPC("RelayTransactionSet", tp.RelayTransactionSet) g.RegisterRPC("RelayTransaction", tp.RelayTransaction) // COMPAT v0.3.3.3 // Subscribe the transaction pool to the consensus set. cs.ConsensusSetSubscribe(tp) return tp, nil }
// New creates a transaction pool that is ready to receive transactions. func New(cs modules.ConsensusSet, g modules.Gateway, persistDir string) (*TransactionPool, error) { // Check that the input modules are non-nil. if cs == nil { return nil, errNilCS } if g == nil { return nil, errNilGateway } // Initialize a transaction pool. tp := &TransactionPool{ consensusSet: cs, gateway: g, knownObjects: make(map[ObjectID]TransactionSetID), transactionSets: make(map[TransactionSetID][]types.Transaction), transactionSetDiffs: make(map[TransactionSetID]modules.ConsensusChange), persistDir: persistDir, } // Open the tpool database. err := tp.initPersist() if err != nil { return nil, err } // Register RPCs g.RegisterRPC("RelayTransactionSet", tp.relayTransactionSet) return tp, nil }
// New returns a new ConsensusSet, containing at least the genesis block. If // there is an existing block database present in the persist directory, it // will be loaded. func New(gateway modules.Gateway, persistDir string) (*ConsensusSet, error) { // Check for nil dependencies. if gateway == nil { return nil, errNilGateway } // Create the genesis block. genesisBlock := types.Block{ Timestamp: types.GenesisTimestamp, Transactions: []types.Transaction{ {SiafundOutputs: types.GenesisSiafundAllocation}, }, } // Create the ConsensusSet object. cs := &ConsensusSet{ gateway: gateway, blockRoot: processedBlock{ Block: genesisBlock, ChildTarget: types.RootTarget, Depth: types.RootDepth, DiffsGenerated: true, }, dosBlocks: make(map[types.BlockID]struct{}), marshaler: encoding.StdGenericMarshaler{}, blockRuleHelper: stdBlockRuleHelper{}, blockValidator: NewBlockValidator(), persistDir: persistDir, } // Create the diffs for the genesis siafund outputs. for i, siafundOutput := range genesisBlock.Transactions[0].SiafundOutputs { sfid := genesisBlock.Transactions[0].SiafundOutputID(uint64(i)) sfod := modules.SiafundOutputDiff{ Direction: modules.DiffApply, ID: sfid, SiafundOutput: siafundOutput, } cs.blockRoot.SiafundOutputDiffs = append(cs.blockRoot.SiafundOutputDiffs, sfod) } // Initialize the consensus persistence structures. err := cs.initPersist() if err != nil { return nil, err } // Register RPCs gateway.RegisterRPC("SendBlocks", cs.sendBlocks) gateway.RegisterRPC("RelayBlock", cs.relayBlock) gateway.RegisterConnectCall("SendBlocks", cs.threadedReceiveBlocks) return cs, nil }
// New creates a transaction pool that is ready to receive transactions. func New(cs modules.ConsensusSet, g modules.Gateway) (tp *TransactionPool, err error) { // Check that the input modules are non-nil. if cs == nil { err = errors.New("transaction pool cannot use a nil state") return } if g == nil { err = errors.New("transaction pool cannot use a nil gateway") return } // Initialize a transaction pool. tp = &TransactionPool{ consensusSet: cs, gateway: g, transactions: make(map[crypto.Hash]struct{}), siacoinOutputs: make(map[types.SiacoinOutputID]types.SiacoinOutput), fileContracts: make(map[types.FileContractID]types.FileContract), siafundOutputs: make(map[types.SiafundOutputID]types.SiafundOutput), referenceSiacoinOutputs: make(map[types.SiacoinOutputID]types.SiacoinOutput), referenceFileContracts: make(map[types.FileContractID]types.FileContract), referenceSiafundOutputs: make(map[types.SiafundOutputID]types.SiafundOutput), mu: sync.New(modules.SafeMutexDelay, 1), } // Register RPCs g.RegisterRPC("RelayTransaction", tp.RelayTransaction) // Subscribe the transaction pool to the consensus set. cs.ConsensusSetSubscribe(tp) return }
// New creates a transaction pool that is ready to receive transactions. func New(cs modules.ConsensusSet, g modules.Gateway) (*TransactionPool, error) { // Check that the input modules are non-nil. if cs == nil { return nil, errNilCS } if g == nil { return nil, errNilGateway } // Initialize a transaction pool. tp := &TransactionPool{ consensusSet: cs, gateway: g, knownObjects: make(map[ObjectID]TransactionSetID), transactionSets: make(map[TransactionSetID][]types.Transaction), transactionSetDiffs: make(map[TransactionSetID]modules.ConsensusChange), // The consensus change index is intialized to '-1', which indicates // that no consensus changes have been sent yet. The first consensus // change will then have an index of '0'. consensusChangeIndex: -1, } // Register RPCs // TODO: rename RelayTransactionSet so that the conflicting RPC // RelayTransaction calls v0.4.6 clients and earlier are ignored. g.RegisterRPC("RelayTransactionSet", tp.relayTransactionSet) // Subscribe the transaction pool to the consensus set. err := cs.ConsensusSetPersistentSubscribe(tp, modules.ConsensusChangeID{}) if err != nil { return nil, errors.New("transactionpool subscription failed: " + err.Error()) } return tp, nil }
// startDaemonCmd uses the config parameters to start siad. func startDaemon(config Config) (err error) { // Prompt user for API password. var password string if config.Siad.AuthenticateAPI { password, err = speakeasy.Ask("Enter API password: "******"" { return errors.New("password cannot be blank") } passwordConfirm, err := speakeasy.Ask("Confirm API password: "******"passwords don't match") } } // Print a startup message. fmt.Println("Loading...") loadStart := time.Now() // Create all of the modules. i := 0 var g modules.Gateway if strings.Contains(config.Siad.Modules, "g") { i++ fmt.Printf("(%d/%d) Loading gateway...\n", i, len(config.Siad.Modules)) g, err = gateway.New(config.Siad.RPCaddr, filepath.Join(config.Siad.SiaDir, modules.GatewayDir)) if err != nil { return err } } var cs modules.ConsensusSet if strings.Contains(config.Siad.Modules, "c") { i++ fmt.Printf("(%d/%d) Loading consensus...\n", i, len(config.Siad.Modules)) cs, err = consensus.New(g, filepath.Join(config.Siad.SiaDir, modules.ConsensusDir)) if err != nil { return err } } var e modules.Explorer if strings.Contains(config.Siad.Modules, "e") { i++ fmt.Printf("(%d/%d) Loading explorer...\n", i, len(config.Siad.Modules)) e, err = explorer.New(cs, filepath.Join(config.Siad.SiaDir, modules.ExplorerDir)) if err != nil { return err } } var tpool modules.TransactionPool if strings.Contains(config.Siad.Modules, "t") { i++ fmt.Printf("(%d/%d) Loading transaction pool...\n", i, len(config.Siad.Modules)) tpool, err = transactionpool.New(cs, g, filepath.Join(config.Siad.SiaDir, modules.TransactionPoolDir)) if err != nil { return err } } var w modules.Wallet if strings.Contains(config.Siad.Modules, "w") { i++ fmt.Printf("(%d/%d) Loading wallet...\n", i, len(config.Siad.Modules)) w, err = wallet.New(cs, tpool, filepath.Join(config.Siad.SiaDir, modules.WalletDir)) if err != nil { return err } } var m modules.Miner if strings.Contains(config.Siad.Modules, "m") { i++ fmt.Printf("(%d/%d) Loading miner...\n", i, len(config.Siad.Modules)) m, err = miner.New(cs, tpool, w, filepath.Join(config.Siad.SiaDir, modules.MinerDir)) if err != nil { return err } } var h modules.Host if strings.Contains(config.Siad.Modules, "h") { i++ fmt.Printf("(%d/%d) Loading host...\n", i, len(config.Siad.Modules)) h, err = host.New(cs, tpool, w, config.Siad.HostAddr, filepath.Join(config.Siad.SiaDir, modules.HostDir)) if err != nil { return err } } var r modules.Renter if strings.Contains(config.Siad.Modules, "r") { i++ fmt.Printf("(%d/%d) Loading renter...\n", i, len(config.Siad.Modules)) r, err = renter.New(cs, w, tpool, filepath.Join(config.Siad.SiaDir, modules.RenterDir)) if err != nil { return err } } srv, err := api.NewServer( config.Siad.APIaddr, config.Siad.RequiredUserAgent, password, cs, e, g, h, m, r, tpool, w, ) if err != nil { return err } // Bootstrap to the network. if !config.Siad.NoBootstrap && g != nil { // connect to 3 random bootstrap nodes perm, err := crypto.Perm(len(modules.BootstrapPeers)) if err != nil { return err } for _, i := range perm[:3] { go g.Connect(modules.BootstrapPeers[i]) } } // Print a 'startup complete' message. startupTime := time.Since(loadStart) fmt.Println("Finished loading in", startupTime.Seconds(), "seconds") // Start serving api requests. err = srv.Serve() if err != nil { return err } return nil }
// New returns a new State, containing at least the genesis block. If there is // an existing block database present in saveDir, it will be loaded. Otherwise, // a new database will be created. func New(gateway modules.Gateway, saveDir string) (*State, error) { if gateway == nil { return nil, ErrNilGateway } // Create the State object. cs := &State{ blockMap: make(map[types.BlockID]*blockNode), dosBlocks: make(map[types.BlockID]struct{}), currentPath: make([]types.BlockID, 1), siacoinOutputs: make(map[types.SiacoinOutputID]types.SiacoinOutput), fileContracts: make(map[types.FileContractID]types.FileContract), siafundOutputs: make(map[types.SiafundOutputID]types.SiafundOutput), delayedSiacoinOutputs: make(map[types.BlockHeight]map[types.SiacoinOutputID]types.SiacoinOutput), gateway: gateway, mu: sync.New(modules.SafeMutexDelay, 1), } // Create the genesis block and add it as the BlockRoot. genesisBlock := types.Block{ Timestamp: types.GenesisTimestamp, Transactions: []types.Transaction{ {SiafundOutputs: types.GenesisSiafundAllocation}, }, } cs.blockRoot = &blockNode{ block: genesisBlock, childTarget: types.RootTarget, depth: types.RootDepth, diffsGenerated: true, } cs.blockMap[genesisBlock.ID()] = cs.blockRoot // Fill out the consensus information for the genesis block. cs.currentPath[0] = genesisBlock.ID() cs.siacoinOutputs[genesisBlock.MinerPayoutID(0)] = types.SiacoinOutput{ Value: types.CalculateCoinbase(0), UnlockHash: types.ZeroUnlockHash, } // Allocate the Siafund addresses by putting them all in a big transaction // and applying the diffs. for i, siafundOutput := range genesisBlock.Transactions[0].SiafundOutputs { sfid := genesisBlock.Transactions[0].SiafundOutputID(i) sfod := modules.SiafundOutputDiff{ Direction: modules.DiffApply, ID: sfid, SiafundOutput: siafundOutput, } cs.commitSiafundOutputDiff(sfod, modules.DiffApply) cs.blockRoot.siafundOutputDiffs = append(cs.blockRoot.siafundOutputDiffs, sfod) } // Send out genesis block update. cs.updateSubscribers(nil, []*blockNode{cs.blockRoot}) // Create the consensus directory. err := os.MkdirAll(saveDir, 0700) if err != nil { return nil, err } // During short tests, use an in-memory database. if build.Release == "testing" && testing.Short() { cs.db = persist.NilDB } else { // Otherwise, try to load an existing database from disk. err = cs.load(saveDir) if err != nil { return nil, err } } // Register RPCs gateway.RegisterRPC("SendBlocks", cs.sendBlocks) gateway.RegisterRPC("RelayBlock", cs.RelayBlock) gateway.RegisterConnectCall("SendBlocks", cs.receiveBlocks) // Spawn resynchronize loop. go cs.threadedResynchronize() return cs, nil }
// startDaemon uses the config parameters to initialize Sia modules and start // siad. func startDaemon(config Config) (err error) { // Prompt user for API password. if config.Siad.AuthenticateAPI { config.APIPassword, err = speakeasy.Ask("Enter API password: "******"" { return errors.New("password cannot be blank") } } // Process the config variables after they are parsed by cobra. config, err = processConfig(config) if err != nil { return err } // Print a startup message. fmt.Println("Loading...") loadStart := time.Now() // Create the server and start serving daemon routes immediately. fmt.Printf("(0/%d) Loading siad...\n", len(config.Siad.Modules)) srv, err := NewServer(config.Siad.APIaddr, config.Siad.RequiredUserAgent, config.APIPassword) if err != nil { return err } servErrs := make(chan error) go func() { servErrs <- srv.Serve() }() // Initialize the Sia modules i := 0 var g modules.Gateway if strings.Contains(config.Siad.Modules, "g") { i++ fmt.Printf("(%d/%d) Loading gateway...\n", i, len(config.Siad.Modules)) g, err = gateway.New(config.Siad.RPCaddr, !config.Siad.NoBootstrap, filepath.Join(config.Siad.SiaDir, modules.GatewayDir)) if err != nil { return err } defer g.Close() } var cs modules.ConsensusSet if strings.Contains(config.Siad.Modules, "c") { i++ fmt.Printf("(%d/%d) Loading consensus...\n", i, len(config.Siad.Modules)) cs, err = consensus.New(g, !config.Siad.NoBootstrap, filepath.Join(config.Siad.SiaDir, modules.ConsensusDir)) if err != nil { return err } defer cs.Close() } var e modules.Explorer if strings.Contains(config.Siad.Modules, "e") { i++ fmt.Printf("(%d/%d) Loading explorer...\n", i, len(config.Siad.Modules)) e, err = explorer.New(cs, filepath.Join(config.Siad.SiaDir, modules.ExplorerDir)) if err != nil { return err } defer e.Close() } var tpool modules.TransactionPool if strings.Contains(config.Siad.Modules, "t") { i++ fmt.Printf("(%d/%d) Loading transaction pool...\n", i, len(config.Siad.Modules)) tpool, err = transactionpool.New(cs, g, filepath.Join(config.Siad.SiaDir, modules.TransactionPoolDir)) if err != nil { return err } defer tpool.Close() } var w modules.Wallet if strings.Contains(config.Siad.Modules, "w") { i++ fmt.Printf("(%d/%d) Loading wallet...\n", i, len(config.Siad.Modules)) w, err = wallet.New(cs, tpool, filepath.Join(config.Siad.SiaDir, modules.WalletDir)) if err != nil { return err } defer w.Close() } var m modules.Miner if strings.Contains(config.Siad.Modules, "m") { i++ fmt.Printf("(%d/%d) Loading miner...\n", i, len(config.Siad.Modules)) m, err = miner.New(cs, tpool, w, filepath.Join(config.Siad.SiaDir, modules.MinerDir)) if err != nil { return err } defer m.Close() } var h modules.Host if strings.Contains(config.Siad.Modules, "h") { i++ fmt.Printf("(%d/%d) Loading host...\n", i, len(config.Siad.Modules)) h, err = host.New(cs, tpool, w, config.Siad.HostAddr, filepath.Join(config.Siad.SiaDir, modules.HostDir)) if err != nil { return err } defer h.Close() } var r modules.Renter if strings.Contains(config.Siad.Modules, "r") { i++ fmt.Printf("(%d/%d) Loading renter...\n", i, len(config.Siad.Modules)) r, err = renter.New(cs, w, tpool, filepath.Join(config.Siad.SiaDir, modules.RenterDir)) if err != nil { return err } defer r.Close() } // Create the Sia API a := api.New( config.Siad.RequiredUserAgent, config.APIPassword, cs, e, g, h, m, r, tpool, w, ) // connect the API to the server srv.mux.Handle("/", a) // stop the server if a kill signal is caught sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, os.Kill) go func() { <-sigChan fmt.Println("\rCaught stop signal, quitting...") srv.Close() }() // Print a 'startup complete' message. startupTime := time.Since(loadStart) fmt.Println("Finished loading in", startupTime.Seconds(), "seconds") err = <-servErrs if err != nil { build.Critical(err) } return nil }
// New returns a new ConsensusSet, containing at least the genesis block. If // there is an existing block database present in the persist directory, it // will be loaded. func New(gateway modules.Gateway, bootstrap bool, persistDir string) (*ConsensusSet, error) { // Check for nil dependencies. if gateway == nil { return nil, errNilGateway } // Create the ConsensusSet object. cs := &ConsensusSet{ gateway: gateway, blockRoot: processedBlock{ Block: types.GenesisBlock, ChildTarget: types.RootTarget, Depth: types.RootDepth, DiffsGenerated: true, }, dosBlocks: make(map[types.BlockID]struct{}), marshaler: encoding.StdGenericMarshaler{}, blockRuleHelper: stdBlockRuleHelper{}, blockValidator: NewBlockValidator(), persistDir: persistDir, } // Create the diffs for the genesis siafund outputs. for i, siafundOutput := range types.GenesisBlock.Transactions[0].SiafundOutputs { sfid := types.GenesisBlock.Transactions[0].SiafundOutputID(uint64(i)) sfod := modules.SiafundOutputDiff{ Direction: modules.DiffApply, ID: sfid, SiafundOutput: siafundOutput, } cs.blockRoot.SiafundOutputDiffs = append(cs.blockRoot.SiafundOutputDiffs, sfod) } // Initialize the consensus persistence structures. err := cs.initPersist() if err != nil { return nil, err } go func() { // Sync with the network. Don't sync if we are testing because // typically we don't have any mock peers to synchronize with in // testing. if bootstrap { // We are in a virgin goroutine right now, so calling the threaded // function without a goroutine is okay. err = cs.threadedInitialBlockchainDownload() if err != nil { return } } // threadedInitialBlockchainDownload will release the threadgroup 'Add' // it was holding, so another needs to be grabbed to finish off this // goroutine. err = cs.tg.Add() if err != nil { return } defer cs.tg.Done() // Register RPCs gateway.RegisterRPC("SendBlocks", cs.rpcSendBlocks) gateway.RegisterRPC("RelayBlock", cs.rpcRelayBlock) // COMPATv0.5.1 gateway.RegisterRPC("RelayHeader", cs.threadedRPCRelayHeader) gateway.RegisterRPC("SendBlk", cs.rpcSendBlk) gateway.RegisterConnectCall("SendBlocks", cs.threadedReceiveBlocks) cs.tg.OnStop(func() { cs.gateway.UnregisterRPC("SendBlocks") cs.gateway.UnregisterRPC("RelayBlock") cs.gateway.UnregisterRPC("RelayHeader") cs.gateway.UnregisterRPC("SendBlk") cs.gateway.UnregisterConnectCall("SendBlocks") }) // Mark that we are synced with the network. cs.mu.Lock() cs.synced = true cs.mu.Unlock() }() return cs, nil }
// New returns a new ConsensusSet, containing at least the genesis block. If // there is an existing block database present in saveDir, it will be loaded. // Otherwise, a new database will be created. func New(gateway modules.Gateway, saveDir string) (*ConsensusSet, error) { if gateway == nil { return nil, ErrNilGateway } // Create the genesis block. genesisBlock := types.Block{ Timestamp: types.GenesisTimestamp, Transactions: []types.Transaction{ {SiafundOutputs: types.GenesisSiafundAllocation}, }, } // Create the ConsensusSet object. cs := &ConsensusSet{ gateway: gateway, blockRoot: processedBlock{ Block: genesisBlock, ChildTarget: types.RootTarget, Depth: types.RootDepth, DiffsGenerated: true, }, dosBlocks: make(map[types.BlockID]struct{}), mu: sync.New(modules.SafeMutexDelay, 1), } // Allocate the Siafund addresses by putting them all in a big transaction inside the genesis block for i, siafundOutput := range genesisBlock.Transactions[0].SiafundOutputs { sfid := genesisBlock.Transactions[0].SiafundOutputID(i) sfod := modules.SiafundOutputDiff{ Direction: modules.DiffApply, ID: sfid, SiafundOutput: siafundOutput, } cs.blockRoot.SiafundOutputDiffs = append(cs.blockRoot.SiafundOutputDiffs, sfod) } // Create the consensus directory. err := os.MkdirAll(saveDir, 0700) if err != nil { return nil, err } // Try to load an existing database from disk. err = cs.load(saveDir) if err != nil { return nil, err } // Send the genesis block to subscribers. cs.updateSubscribers(nil, []*processedBlock{&cs.blockRoot}) // Send any blocks that were loaded from disk to subscribers. cs.loadDiffs() // Register RPCs gateway.RegisterRPC("SendBlocks", cs.sendBlocks) gateway.RegisterRPC("RelayBlock", cs.RelayBlock) gateway.RegisterConnectCall("SendBlocks", cs.receiveBlocks) return cs, nil }
// New returns a new ConsensusSet, containing at least the genesis block. If // there is an existing block database present in the persist directory, it // will be loaded. func New(gateway modules.Gateway, persistDir string) (*ConsensusSet, error) { // Check for nil dependencies. if gateway == nil { return nil, errNilGateway } // Create the ConsensusSet object. cs := &ConsensusSet{ gateway: gateway, blockRoot: processedBlock{ Block: types.GenesisBlock, ChildTarget: types.RootTarget, Depth: types.RootDepth, DiffsGenerated: true, }, dosBlocks: make(map[types.BlockID]struct{}), marshaler: encoding.StdGenericMarshaler{}, blockRuleHelper: stdBlockRuleHelper{}, blockValidator: NewBlockValidator(), persistDir: persistDir, } // Create the diffs for the genesis siafund outputs. for i, siafundOutput := range types.GenesisBlock.Transactions[0].SiafundOutputs { sfid := types.GenesisBlock.Transactions[0].SiafundOutputID(uint64(i)) sfod := modules.SiafundOutputDiff{ Direction: modules.DiffApply, ID: sfid, SiafundOutput: siafundOutput, } cs.blockRoot.SiafundOutputDiffs = append(cs.blockRoot.SiafundOutputDiffs, sfod) } // Initialize the consensus persistence structures. err := cs.initPersist() if err != nil { return nil, err } go func() { // Sync with the network. Don't sync if we are testing because typically we // don't have any mock peers to synchronize with in testing. // TODO: figure out a better way to conditionally do IBD. Otherwise this block will never be tested. if build.Release != "testing" { cs.threadedInitialBlockchainDownload() } // Register RPCs gateway.RegisterRPC("SendBlocks", cs.rpcSendBlocks) gateway.RegisterRPC("RelayBlock", cs.rpcRelayBlock) // COMPATv0.5.1 gateway.RegisterRPC("RelayHeader", cs.rpcRelayHeader) gateway.RegisterRPC("SendBlk", cs.rpcSendBlk) gateway.RegisterConnectCall("SendBlocks", cs.threadedReceiveBlocks) // Mark that we are synced with the network. cs.mu.Lock() cs.synced = true cs.mu.Unlock() }() return cs, nil }