Beispiel #1
0
// New creates the internal data structures, and subscribes to
// consensus for changes to the blockchain
func New(cs modules.ConsensusSet, persistDir string) (*Explorer, error) {
	// Check that input modules are non-nil
	if cs == nil {
		return nil, errNilCS
	}

	// Initialize the explorer.
	e := &Explorer{
		currentBlock:   cs.GenesisBlock(),
		genesisBlockID: cs.GenesisBlock().ID(),
		seenTimes:      make([]time.Time, types.MaturityDelay+1),
		startTime:      time.Now(),

		cs:         cs,
		persistDir: persistDir,
	}
	e.blockchainHeight-- // Set to -1 so the genesis block sets the height to 0.

	// Intialize the persistent structures, including the database.
	err := e.initPersist()
	if err != nil {
		return nil, err
	}

	cs.ConsensusSetSubscribe(e)

	return e, nil
}
Beispiel #2
0
// New creates the internal data structures, and subscribes to
// consensus for changes to the blockchain
func New(cs modules.ConsensusSet, persistDir string) (*Explorer, error) {
	// Check that input modules are non-nil
	if cs == nil {
		return nil, errNilCS
	}

	// Initialize the explorer.
	e := &Explorer{
		blocksDifficulty:      types.RootDepth,
		blockHashes:           make(map[types.BlockID]types.BlockHeight),
		blockTargets:          make(map[types.BlockID]types.Target),
		transactionHashes:     make(map[types.TransactionID]types.BlockHeight),
		unlockHashes:          make(map[types.UnlockHash]map[types.TransactionID]struct{}),
		siacoinOutputIDs:      make(map[types.SiacoinOutputID]map[types.TransactionID]struct{}),
		siacoinOutputs:        make(map[types.SiacoinOutputID]types.SiacoinOutput),
		fileContractIDs:       make(map[types.FileContractID]map[types.TransactionID]struct{}),
		fileContractHistories: make(map[types.FileContractID]*fileContractHistory),
		siafundOutputIDs:      make(map[types.SiafundOutputID]map[types.TransactionID]struct{}),
		siafundOutputs:        make(map[types.SiafundOutputID]types.SiafundOutput),

		cs:         cs,
		persistDir: persistDir,
	}
	e.blockchainHeight-- // Set to -1 so the genesis block sets the height to 0.

	// Intialize the persistent structures, including the database.
	err := e.initPersist()
	if err != nil {
		return nil, err
	}

	cs.ConsensusSetPersistentSubscribe(e, modules.ConsensusChangeID{})

	return e, nil
}
Beispiel #3
0
// New creates the internal data structures, and subscribes to
// consensus for changes to the blockchain
func New(cs modules.ConsensusSet, persistDir string) (*Explorer, error) {
	// Check that input modules are non-nil
	if cs == nil {
		return nil, errNilCS
	}

	// Initialize the explorer.
	e := &Explorer{
		cs:         cs,
		persistDir: persistDir,
	}

	// Initialize the persistent structures, including the database.
	err := e.initPersist()
	if err != nil {
		return nil, err
	}

	// retrieve the current ConsensusChangeID
	var recentChange modules.ConsensusChangeID
	err = e.db.View(dbGetInternal(internalRecentChange, &recentChange))
	if err != nil {
		return nil, err
	}

	err = cs.ConsensusSetSubscribe(e, recentChange)
	if err != nil {
		// TODO: restart from 0
		return nil, errors.New("explorer subscription failed: " + err.Error())
	}

	return e, nil
}
Beispiel #4
0
// 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
}
Beispiel #5
0
// newAnnouncementFinder will create and return an announcement finder.
func newAnnouncementFinder(cs modules.ConsensusSet) (*announcementFinder, error) {
	af := &announcementFinder{
		cs: cs,
	}
	err := cs.ConsensusSetSubscribe(af, modules.ConsensusChangeBeginning)
	if err != nil {
		return nil, err
	}
	return af, nil
}
Beispiel #6
0
// New returns an empty renter.
func New(cs modules.ConsensusSet, hdb modules.HostDB, wallet modules.Wallet, tpool modules.TransactionPool, persistDir string) (*Renter, error) {
	if cs == nil {
		return nil, ErrNilCS
	}
	if hdb == nil {
		return nil, ErrNilHostDB
	}
	if wallet == nil {
		return nil, ErrNilWallet
	}
	if tpool == nil {
		return nil, ErrNilTpool
	}

	r := &Renter{
		cs:     cs,
		hostDB: hdb,
		wallet: wallet,
		tpool:  tpool,

		files:     make(map[string]*file),
		contracts: make(map[types.FileContractID]types.FileContract),
		repairSet: make(map[string]string),

		persistDir: persistDir,
		mu:         sync.New(modules.SafeMutexDelay, 1),
	}
	_, err := rand.Read(r.entropy[:])
	if err != nil {
		return nil, err
	}
	err = r.initPersist()
	if err != nil {
		return nil, err
	}

	cs.ConsensusSetSubscribe(r)

	go r.threadedRepairUploads()

	return r, nil
}
Beispiel #7
0
// New creates and starts up a hostdb. The hostdb that gets returned will not
// have finished scanning the network or blockchain.
func New(cs modules.ConsensusSet, wallet modules.Wallet, tpool modules.TransactionPool, persistDir string) (*HostDB, error) {
	if cs == nil {
		return nil, errNilCS
	}
	if wallet == nil {
		return nil, errNilWallet
	}
	if tpool == nil {
		return nil, errNilTpool
	}

	hdb := &HostDB{
		cs:     cs,
		wallet: wallet,
		tpool:  tpool,

		contracts:   make(map[types.FileContractID]hostContract),
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),

		persistDir: persistDir,
	}
	err := hdb.initPersist()
	if err != nil {
		return nil, err
	}

	// Begin listening to consensus and looking for hosts.
	for i := 0; i < scanningThreads; i++ {
		go hdb.threadedProbeHosts()
	}
	go hdb.threadedScan()

	cs.ConsensusSetSubscribe(hdb)

	return hdb, nil
}
Beispiel #8
0
// New creates the internal data structures, and subscribes to
// consensus for changes to the blockchain
func New(cs modules.ConsensusSet) (be *BlockExplorer, err error) {
	// Check that input modules are non-nil
	if cs == nil {
		err = errors.New("Blockchain explorer cannot use a nil ConsensusSet")
		return
	}

	// Initilize the module state
	be = &BlockExplorer{
		currentBlock:       cs.GenesisBlock(),
		genesisBlockID:     cs.GenesisBlock().ID(),
		blockchainHeight:   0,
		currencySent:       types.NewCurrency64(0),
		activeContractCost: types.NewCurrency64(0),
		totalContractCost:  types.NewCurrency64(0),
		cs:                 cs,
		mu:                 sync.New(modules.SafeMutexDelay, 1),
	}

	cs.ConsensusSetSubscribe(be)

	return
}
Beispiel #9
0
// 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
}
Beispiel #10
0
// New creates and starts up a hostdb. The hostdb that gets returned will not
// have finished scanning the network or blockchain.
func New(cs modules.ConsensusSet, g modules.Gateway, persistDir string) (*HostDB, error) {
	// Check for nil dependencies.
	if cs == nil {
		return nil, errNilConsensusSet
	}
	if g == nil {
		return nil, errNilGateway
	}

	// Build an empty hostdb.
	hdb := &HostDB{
		consensusSet: cs,
		gateway:      g,

		activeHosts: make(map[modules.NetAddress]*hostNode),

		allHosts: make(map[modules.NetAddress]*hostEntry),

		scanPool: make(chan *hostEntry, scanPoolSize),

		persistDir: persistDir,
		mu:         sync.New(modules.SafeMutexDelay, 1),
	}
	err := hdb.initPersist()
	if err != nil {
		return nil, err
	}

	// Begin listening to consensus and looking for hosts.
	for i := 0; i < scanningThreads; i++ {
		go hdb.threadedProbeHosts()
	}
	go hdb.threadedScan()
	cs.ConsensusSetSubscribe(hdb)
	return hdb, nil
}
Beispiel #11
0
// 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
}
Beispiel #12
0
Datei: miner.go Projekt: mm3/Sia
// New returns a ready-to-go miner that is not mining.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, w modules.Wallet, persistDir string) (*Miner, error) {
	// Create the miner and its dependencies.
	if cs == nil {
		return nil, errors.New("miner cannot use a nil state")
	}
	if tpool == nil {
		return nil, errors.New("miner cannot use a nil transaction pool")
	}
	if w == nil {
		return nil, errors.New("miner cannot use a nil wallet")
	}

	// Grab some starting block variables.
	currentBlock := cs.GenesisBlock().ID()
	currentTarget, exists1 := cs.ChildTarget(currentBlock)
	earliestTimestamp, exists2 := cs.EarliestChildTimestamp(currentBlock)
	if build.DEBUG {
		if !exists1 {
			panic("could not get child target")
		}
		if !exists2 {
			panic("could not get child earliest timestamp")
		}
	}
	addr, _, err := w.CoinAddress(false) // false indicates that the address should not be visible to the user.
	if err != nil {
		return nil, err
	}

	// Assemble the miner.
	m := &Miner{
		cs:     cs,
		tpool:  tpool,
		wallet: w,

		parent:            currentBlock,
		target:            currentTarget,
		earliestTimestamp: earliestTimestamp,
		address:           addr,

		blockMem:  make(map[types.BlockHeader]types.Block),
		headerMem: make([]types.BlockHeader, headerForWorkMemory),

		persistDir: persistDir,
		mu:         sync.New(modules.SafeMutexDelay, 1),
	}
	err = m.initPersist()
	if err != nil {
		return nil, err
	}
	m.tpool.TransactionPoolSubscribe(m)
	return m, nil
}
Beispiel #13
0
// New returns a ready-to-go miner that is not mining.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, w modules.Wallet, persistDir string) (*Miner, error) {
	// Create the miner and its dependencies.
	if cs == nil {
		return nil, errors.New("miner cannot use a nil state")
	}
	if tpool == nil {
		return nil, errors.New("miner cannot use a nil transaction pool")
	}
	if w == nil {
		return nil, errors.New("miner cannot use a nil wallet")
	}

	// Grab some starting block variables.
	currentBlock := cs.GenesisBlock().ID()
	currentTarget, exists1 := cs.ChildTarget(currentBlock)
	earliestTimestamp, exists2 := cs.EarliestChildTimestamp(currentBlock)
	if build.DEBUG {
		if !exists1 {
			panic("could not get child target")
		}
		if !exists2 {
			panic("could not get child earliest timestamp")
		}
	}

	// Assemble the miner. The miner is assembled without an address because
	// the wallet is likely not unlocked yet. The miner will grab an address
	// after the miner is unlocked (this must be coded manually for each
	// function that potentially requires the miner to have an address.
	m := &Miner{
		cs:     cs,
		tpool:  tpool,
		wallet: w,

		parent:            currentBlock,
		target:            currentTarget,
		earliestTimestamp: earliestTimestamp,

		blockMem:   make(map[types.BlockHeader]*types.Block),
		arbDataMem: make(map[types.BlockHeader][]byte),
		headerMem:  make([]types.BlockHeader, headerForWorkMemory),

		persistDir: persistDir,
		mu:         sync.New(modules.SafeMutexDelay, 1),
	}
	err := m.initPersist()
	if err != nil {
		return nil, err
	}
	m.tpool.TransactionPoolSubscribe(m)
	return m, nil
}
Beispiel #14
0
func dbCalculateBlockFacts(tx *bolt.Tx, cs modules.ConsensusSet, block types.Block) blockFacts {
	// get the parent block facts
	var bf blockFacts
	err := dbGetAndDecode(bucketBlockFacts, block.ParentID, &bf)(tx)
	assertNil(err)

	// get target
	target, exists := cs.ChildTarget(block.ParentID)
	if !exists {
		panic(fmt.Sprint("ConsensusSet is missing target of known block", block.ParentID))
	}

	// update fields
	bf.BlockID = block.ID()
	bf.Height++
	bf.Difficulty = target.Difficulty()
	bf.Target = target
	bf.Timestamp = block.Timestamp
	bf.TotalCoins = types.CalculateNumSiacoins(bf.Height)

	// calculate maturity timestamp
	var maturityTimestamp types.Timestamp
	if bf.Height > types.MaturityDelay {
		oldBlock, exists := cs.BlockAtHeight(bf.Height - types.MaturityDelay)
		if !exists {
			panic(fmt.Sprint("ConsensusSet is missing block at height", bf.Height-types.MaturityDelay))
		}
		maturityTimestamp = oldBlock.Timestamp
	}
	bf.MaturityTimestamp = maturityTimestamp

	// calculate hashrate by averaging last 'hashrateEstimationBlocks' blocks
	var estimatedHashrate types.Currency
	if bf.Height > hashrateEstimationBlocks {
		var totalDifficulty = bf.Target
		var oldestTimestamp types.Timestamp
		for i := types.BlockHeight(1); i < hashrateEstimationBlocks; i++ {
			b, exists := cs.BlockAtHeight(bf.Height - i)
			if !exists {
				panic(fmt.Sprint("ConsensusSet is missing block at height", bf.Height-hashrateEstimationBlocks))
			}
			target, exists := cs.ChildTarget(b.ParentID)
			if !exists {
				panic(fmt.Sprint("ConsensusSet is missing target of known block", b.ParentID))
			}
			totalDifficulty = totalDifficulty.AddDifficulties(target)
			oldestTimestamp = b.Timestamp
		}
		secondsPassed := bf.Timestamp - oldestTimestamp
		estimatedHashrate = totalDifficulty.Difficulty().Div64(uint64(secondsPassed))
	}
	bf.EstimatedHashrate = estimatedHashrate

	bf.MinerPayoutCount += uint64(len(block.MinerPayouts))
	bf.TransactionCount += uint64(len(block.Transactions))
	for _, txn := range block.Transactions {
		bf.SiacoinInputCount += uint64(len(txn.SiacoinInputs))
		bf.SiacoinOutputCount += uint64(len(txn.SiacoinOutputs))
		bf.FileContractCount += uint64(len(txn.FileContracts))
		bf.FileContractRevisionCount += uint64(len(txn.FileContractRevisions))
		bf.StorageProofCount += uint64(len(txn.StorageProofs))
		bf.SiafundInputCount += uint64(len(txn.SiafundInputs))
		bf.SiafundOutputCount += uint64(len(txn.SiafundOutputs))
		bf.MinerFeeCount += uint64(len(txn.MinerFees))
		bf.ArbitraryDataCount += uint64(len(txn.ArbitraryData))
		bf.TransactionSignatureCount += uint64(len(txn.TransactionSignatures))

		for _, fc := range txn.FileContracts {
			bf.TotalContractCost = bf.TotalContractCost.Add(fc.Payout)
			bf.TotalContractSize = bf.TotalContractSize.Add(types.NewCurrency64(fc.FileSize))
		}
		for _, fcr := range txn.FileContractRevisions {
			bf.TotalContractSize = bf.TotalContractSize.Add(types.NewCurrency64(fcr.NewFileSize))
			bf.TotalRevisionVolume = bf.TotalRevisionVolume.Add(types.NewCurrency64(fcr.NewFileSize))
		}
	}

	return bf
}
Beispiel #15
0
// 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
}