Пример #1
0
// OpenDB creates and opens the database for the block explorer. Sholud be run on startup
func openDB(filename string) (*explorerDB, error) {
	db, err := persist.OpenDatabase(meta, filename)
	if err != nil {
		return nil, err
	}

	var buckets []string = []string{
		"Blocks", "Transactions", "Addresses",
		"FileContracts", "SiacoinOutputs", "SiafundOutputs",
		"Heights", "Hashes",
	}

	// Create buckets
	err = db.Update(func(tx *bolt.Tx) error {
		for _, bucketName := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(bucketName))
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	return &explorerDB{db}, nil
}
Пример #2
0
// openDB loads the set database and populates it with the necessary buckets
func (cs *ConsensusSet) openDB(filename string) (err error) {
	cs.db, err = persist.OpenDatabase(dbMetadata, filename)
	if err == persist.ErrBadVersion {
		return cs.replaceDatabase(filename)
	}
	if err != nil {
		return errors.New("error opening consensus database: " + err.Error())
	}
	return nil
}
Пример #3
0
// initPersist creates buckets in the database
func (tp *TransactionPool) initPersist() error {
	// Create the persist directory if it does not yet exist.
	err := os.MkdirAll(tp.persistDir, 0700)
	if err != nil {
		return err
	}

	// Open the database file.
	tp.db, err = persist.OpenDatabase(dbMetadata, filepath.Join(tp.persistDir, dbFilename))
	if err != nil {
		return err
	}

	// Create the database and get the most recent consensus change.
	var cc modules.ConsensusChangeID
	err = tp.db.Update(func(tx *bolt.Tx) error {
		// Create the database buckets.
		buckets := [][]byte{
			bucketRecentConsensusChange,
			bucketConfirmedTransactions,
		}
		for _, bucket := range buckets {
			_, err := tx.CreateBucketIfNotExists(bucket)
			if err != nil {
				return err
			}
		}

		// Get the recent consensus change.
		cc, err = tp.getRecentConsensusChange(tx)
		if err == errNilConsensusChange {
			return tp.putRecentConsensusChange(tx, modules.ConsensusChangeBeginning)
		}
		return err
	})
	if err != nil {
		return err
	}

	// Subscribe to the consensus set using the most recent consensus change.
	err = tp.consensusSet.ConsensusSetSubscribe(tp, cc)
	if err == modules.ErrInvalidConsensusChangeID {
		// Reset and rescan because the consensus set does not recognize the
		// provided consensus change id.
		resetErr := tp.db.Update(func(tx *bolt.Tx) error {
			return tp.resetDB(tx)
		})
		if resetErr != nil {
			return resetErr
		}
		return tp.consensusSet.ConsensusSetSubscribe(tp, modules.ConsensusChangeBeginning)
	}
	return err
}
Пример #4
0
// replaceDatabase backs up the existing database and creates a new one.
func (cs *ConsensusSet) replaceDatabase(filename string) error {
	// Rename the existing database and create a new one.
	fmt.Println("Outdated consensus database... backing up and replacing")
	err := os.Rename(filename, filename+".bck")
	if err != nil {
		return errors.New("error while backing up consensus database: " + err.Error())
	}

	// Try again to create a new database, this time without checking for an
	// outdated database error.
	cs.db, err = persist.OpenDatabase(dbMetadata, filename)
	if err != nil {
		return errors.New("error opening consensus database: " + err.Error())
	}
	return nil
}
Пример #5
0
// openDB loads the set database and populates it with the necessary buckets
func openDB(filename string) (*setDB, error) {
	db, err := persist.OpenDatabase(meta, filename)
	if err != nil {
		return nil, err
	}

	// Enumerate the database buckets.
	buckets := [][]byte{
		BlockPath,
		BlockMap,
		SiacoinOutputs,
		FileContracts,
		FileContractExpirations,
		SiafundOutputs,
		SiafundPool,
		DSCOBuckets,
	}

	// Initialize the database.
	err = db.Update(func(tx *bolt.Tx) error {
		// Create the database buckets.
		for _, bucket := range buckets {
			_, err := tx.CreateBucketIfNotExists(bucket)
			if err != nil {
				return err
			}
		}

		// Initilize the consistency guards.
		cg, err := tx.CreateBucketIfNotExists(ConsistencyGuard)
		if err != nil {
			return err
		}
		gs := cg.Get(GuardStart)
		ge := cg.Get(GuardEnd)
		// Database is consistent if both are nil, or if both are equal.
		// Database is inconsistent otherwise.
		if (gs != nil && ge != nil && bytes.Equal(gs, ge)) || gs == nil && ge == nil {
			cg.Put(GuardStart, encoding.EncUint64(1))
			cg.Put(GuardEnd, encoding.EncUint64(1))
			return nil
		}
		return errDBInconsistent
	})
	return &setDB{db, true}, err
}
Пример #6
0
// openDatabase creates a database that the host can use to interact with large
// volumes of persistent data.
func (productionDependencies) openDatabase(m persist.Metadata, s string) (*persist.BoltDatabase, error) {
	return persist.OpenDatabase(m, s)
}
Пример #7
0
// TestRescan triggers a rescan in the transaction pool, verifying that the
// rescan code does not cause deadlocks or crashes.
func TestRescan(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	tpt, err := createTpoolTester("TestRescan")
	if err != nil {
		t.Fatal(err)
	}
	defer tpt.Close()

	// Create a valid transaction set using the wallet.
	txns, err := tpt.wallet.SendSiacoins(types.NewCurrency64(100), types.UnlockHash{})
	if err != nil {
		t.Fatal(err)
	}
	if len(tpt.tpool.transactionSets) != 1 {
		t.Error("sending coins did not increase the transaction sets by 1")
	}
	// Mine the transaction into a block, so that it's in the consensus set.
	_, err = tpt.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}

	// Close the tpool, delete the persistence, then restart the tpool. The
	// tpool should still recognize the transaction set as a duplicate.
	persistDir := tpt.tpool.persistDir
	err = tpt.tpool.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = os.RemoveAll(persistDir)
	if err != nil {
		t.Fatal(err)
	}
	tpt.tpool, err = New(tpt.cs, tpt.gateway, persistDir)
	if err != nil {
		t.Fatal(err)
	}
	err = tpt.tpool.AcceptTransactionSet(txns)
	if err != modules.ErrDuplicateTransactionSet {
		t.Fatal("expecting modules.ErrDuplicateTransactionSet, got:", err)
	}

	// Close the tpool, corrupt the database, then restart the tpool. The tpool
	// should still recognize the transaction set as a duplicate.
	err = tpt.tpool.Close()
	if err != nil {
		t.Fatal(err)
	}
	db, err := persist.OpenDatabase(dbMetadata, filepath.Join(persistDir, dbFilename))
	if err != nil {
		t.Fatal(err)
	}
	err = db.Update(func(tx *bolt.Tx) error {
		ccBytes := tx.Bucket(bucketRecentConsensusChange).Get(fieldRecentConsensusChange)
		// copy the bytes due to bolt's mmap.
		newCCBytes := make([]byte, len(ccBytes))
		copy(newCCBytes, ccBytes)
		newCCBytes[0]++
		return tx.Bucket(bucketRecentConsensusChange).Put(fieldRecentConsensusChange, newCCBytes)
	})
	if err != nil {
		t.Fatal(err)
	}
	err = db.Close()
	if err != nil {
		t.Fatal(err)
	}
	tpt.tpool, err = New(tpt.cs, tpt.gateway, persistDir)
	if err != nil {
		t.Fatal(err)
	}
	err = tpt.tpool.AcceptTransactionSet(txns)
	if err != modules.ErrDuplicateTransactionSet {
		t.Fatal("expecting modules.ErrDuplicateTransactionSet, got:", err)
	}
}
Пример #8
0
// openDB loads the set database and populates it with the necessary buckets
func (cs *ConsensusSet) openDB(filename string) (err error) {
	cs.db, err = persist.OpenDatabase(dbMetadata, filename)
	return err
}
Пример #9
0
// initPersist initializes the persistent structures of the explorer module.
func (e *Explorer) initPersist() error {
	// Make the persist directory
	err := os.MkdirAll(e.persistDir, 0700)
	if err != nil {
		return err
	}

	// Open the database
	db, err := persist.OpenDatabase(explorerMetadata, filepath.Join(e.persistDir, "explorer.db"))
	if err != nil {
		return err
	}
	e.db = db

	// Initialize the database
	err = e.db.Update(func(tx *bolt.Tx) error {
		buckets := [][]byte{
			bucketBlockFacts,
			bucketBlockIDs,
			bucketBlocksDifficulty,
			bucketBlockTargets,
			bucketFileContractHistories,
			bucketFileContractIDs,
			bucketInternal,
			bucketSiacoinOutputIDs,
			bucketSiacoinOutputs,
			bucketSiafundOutputIDs,
			bucketSiafundOutputs,
			bucketTransactionIDs,
			bucketUnlockHashes,
		}
		for _, b := range buckets {
			_, err := tx.CreateBucketIfNotExists(b)
			if err != nil {
				return err
			}
		}

		// set default values for the bucketInternal
		internalDefaults := []struct {
			key, val []byte
		}{
			{internalBlockHeight, encoding.Marshal(types.BlockHeight(0))},
			{internalRecentChange, encoding.Marshal(modules.ConsensusChangeID{})},
		}
		b := tx.Bucket(bucketInternal)
		for _, d := range internalDefaults {
			if b.Get(d.key) != nil {
				continue
			}
			err := b.Put(d.key, d.val)
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}