github.com/btcsuite/btcd@v0.24.0/database/example_test.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package database_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	"github.com/btcsuite/btcd/btcutil"
    15  	"github.com/btcsuite/btcd/chaincfg"
    16  	"github.com/btcsuite/btcd/database"
    17  	_ "github.com/btcsuite/btcd/database/ffldb"
    18  	"github.com/btcsuite/btcd/wire"
    19  )
    20  
    21  // This example demonstrates creating a new database.
    22  func ExampleCreate() {
    23  	// This example assumes the ffldb driver is imported.
    24  	//
    25  	// import (
    26  	// 	"github.com/btcsuite/btcd/database"
    27  	// 	_ "github.com/btcsuite/btcd/database/ffldb"
    28  	// )
    29  
    30  	// Create a database and schedule it to be closed and removed on exit.
    31  	// Typically you wouldn't want to remove the database right away like
    32  	// this, nor put it in the temp directory, but it's done here to ensure
    33  	// the example cleans up after itself.
    34  	dbPath := filepath.Join(os.TempDir(), "examplecreate")
    35  	db, err := database.Create("ffldb", dbPath, wire.MainNet)
    36  	if err != nil {
    37  		fmt.Println(err)
    38  		return
    39  	}
    40  	defer os.RemoveAll(dbPath)
    41  	defer db.Close()
    42  
    43  	// Output:
    44  }
    45  
    46  // This example demonstrates creating a new database and using a managed
    47  // read-write transaction to store and retrieve metadata.
    48  func Example_basicUsage() {
    49  	// This example assumes the ffldb driver is imported.
    50  	//
    51  	// import (
    52  	// 	"github.com/btcsuite/btcd/database"
    53  	// 	_ "github.com/btcsuite/btcd/database/ffldb"
    54  	// )
    55  
    56  	// Create a database and schedule it to be closed and removed on exit.
    57  	// Typically you wouldn't want to remove the database right away like
    58  	// this, nor put it in the temp directory, but it's done here to ensure
    59  	// the example cleans up after itself.
    60  	dbPath := filepath.Join(os.TempDir(), "exampleusage")
    61  	db, err := database.Create("ffldb", dbPath, wire.MainNet)
    62  	if err != nil {
    63  		fmt.Println(err)
    64  		return
    65  	}
    66  	defer os.RemoveAll(dbPath)
    67  	defer db.Close()
    68  
    69  	// Use the Update function of the database to perform a managed
    70  	// read-write transaction.  The transaction will automatically be rolled
    71  	// back if the supplied inner function returns a non-nil error.
    72  	err = db.Update(func(tx database.Tx) error {
    73  		// Store a key/value pair directly in the metadata bucket.
    74  		// Typically a nested bucket would be used for a given feature,
    75  		// but this example is using the metadata bucket directly for
    76  		// simplicity.
    77  		key := []byte("mykey")
    78  		value := []byte("myvalue")
    79  		if err := tx.Metadata().Put(key, value); err != nil {
    80  			return err
    81  		}
    82  
    83  		// Read the key back and ensure it matches.
    84  		if !bytes.Equal(tx.Metadata().Get(key), value) {
    85  			return fmt.Errorf("unexpected value for key '%s'", key)
    86  		}
    87  
    88  		// Create a new nested bucket under the metadata bucket.
    89  		nestedBucketKey := []byte("mybucket")
    90  		nestedBucket, err := tx.Metadata().CreateBucket(nestedBucketKey)
    91  		if err != nil {
    92  			return err
    93  		}
    94  
    95  		// The key from above that was set in the metadata bucket does
    96  		// not exist in this new nested bucket.
    97  		if nestedBucket.Get(key) != nil {
    98  			return fmt.Errorf("key '%s' is not expected nil", key)
    99  		}
   100  
   101  		return nil
   102  	})
   103  	if err != nil {
   104  		fmt.Println(err)
   105  		return
   106  	}
   107  
   108  	// Output:
   109  }
   110  
   111  // This example demonstrates creating a new database, using a managed read-write
   112  // transaction to store a block, and using a managed read-only transaction to
   113  // fetch the block.
   114  func Example_blockStorageAndRetrieval() {
   115  	// This example assumes the ffldb driver is imported.
   116  	//
   117  	// import (
   118  	// 	"github.com/btcsuite/btcd/database"
   119  	// 	_ "github.com/btcsuite/btcd/database/ffldb"
   120  	// )
   121  
   122  	// Create a database and schedule it to be closed and removed on exit.
   123  	// Typically you wouldn't want to remove the database right away like
   124  	// this, nor put it in the temp directory, but it's done here to ensure
   125  	// the example cleans up after itself.
   126  	dbPath, err := ioutil.TempDir("", "exampleblkstorage")
   127  	if err != nil {
   128  		fmt.Println(err)
   129  		return
   130  	}
   131  	db, err := database.Create("ffldb", dbPath, wire.MainNet)
   132  	if err != nil {
   133  		fmt.Println("fail here")
   134  		fmt.Println(err)
   135  		return
   136  	}
   137  	defer os.RemoveAll(dbPath)
   138  	defer db.Close()
   139  
   140  	// Use the Update function of the database to perform a managed
   141  	// read-write transaction and store a genesis block in the database as
   142  	// and example.
   143  	err = db.Update(func(tx database.Tx) error {
   144  		genesisBlock := chaincfg.MainNetParams.GenesisBlock
   145  		return tx.StoreBlock(btcutil.NewBlock(genesisBlock))
   146  	})
   147  	if err != nil {
   148  		fmt.Println(err)
   149  		return
   150  	}
   151  
   152  	// Use the View function of the database to perform a managed read-only
   153  	// transaction and fetch the block stored above.
   154  	var loadedBlockBytes []byte
   155  	err = db.Update(func(tx database.Tx) error {
   156  		genesisHash := chaincfg.MainNetParams.GenesisHash
   157  		blockBytes, err := tx.FetchBlock(genesisHash)
   158  		if err != nil {
   159  			return err
   160  		}
   161  
   162  		// As documented, all data fetched from the database is only
   163  		// valid during a database transaction in order to support
   164  		// zero-copy backends.  Thus, make a copy of the data so it
   165  		// can be used outside of the transaction.
   166  		loadedBlockBytes = make([]byte, len(blockBytes))
   167  		copy(loadedBlockBytes, blockBytes)
   168  		return nil
   169  	})
   170  	if err != nil {
   171  		fmt.Println(err)
   172  		return
   173  	}
   174  
   175  	// Typically at this point, the block could be deserialized via the
   176  	// wire.MsgBlock.Deserialize function or used in its serialized form
   177  	// depending on need.  However, for this example, just display the
   178  	// number of serialized bytes to show it was loaded as expected.
   179  	fmt.Printf("Serialized block size: %d bytes\n", len(loadedBlockBytes))
   180  
   181  	// Output:
   182  	// Serialized block size: 285 bytes
   183  }