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 }