github.com/decred/dcrlnd@v0.7.6/channeldb/migtest/raw_db.go (about) 1 package migtest 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "strings" 9 10 "github.com/decred/dcrlnd/kvdb" 11 ) 12 13 // DumpDB dumps go code describing the contents of the database to stdout. This 14 // function is only intended for use during development. 15 // 16 // Example output: 17 // 18 // map[string]interface{}{ 19 // hex("1234"): map[string]interface{}{ 20 // "human-readable": hex("102030"), 21 // hex("1111"): hex("5783492373"), 22 // }, 23 // } 24 func DumpDB(tx kvdb.RTx, rootKey []byte) error { 25 bucket := tx.ReadBucket(rootKey) 26 if bucket == nil { 27 return fmt.Errorf("bucket %v not found", string(rootKey)) 28 } 29 30 return dumpBucket(bucket) 31 } 32 33 func dumpBucket(bucket kvdb.RBucket) error { 34 fmt.Printf("map[string]interface{} {\n") 35 err := bucket.ForEach(func(k, v []byte) error { 36 key := toString(k) 37 fmt.Printf("%v: ", key) 38 39 subBucket := bucket.NestedReadBucket(k) 40 if subBucket != nil { 41 err := dumpBucket(subBucket) 42 if err != nil { 43 return err 44 } 45 } else { 46 fmt.Print(toHex(v)) 47 } 48 fmt.Printf(",\n") 49 50 return nil 51 }) 52 if err != nil { 53 return err 54 } 55 fmt.Printf("}") 56 57 return nil 58 } 59 60 // RestoreDB primes the database with the given data set. 61 func RestoreDB(tx kvdb.RwTx, rootKey []byte, data map[string]interface{}) error { 62 bucket, err := tx.CreateTopLevelBucket(rootKey) 63 if err != nil { 64 return err 65 } 66 67 return restoreDB(bucket, data) 68 } 69 70 func restoreDB(bucket kvdb.RwBucket, data map[string]interface{}) error { 71 for k, v := range data { 72 key := []byte(k) 73 74 switch value := v.(type) { 75 76 // Key contains value. 77 case string: 78 err := bucket.Put(key, []byte(value)) 79 if err != nil { 80 return err 81 } 82 83 // Key contains a sub-bucket. 84 case map[string]interface{}: 85 subBucket, err := bucket.CreateBucket(key) 86 if err != nil { 87 return err 88 } 89 90 if err := restoreDB(subBucket, value); err != nil { 91 return err 92 } 93 94 default: 95 return errors.New("invalid type") 96 } 97 } 98 99 return nil 100 } 101 102 // VerifyDB verifies the database against the given data set. 103 func VerifyDB(tx kvdb.RTx, rootKey []byte, data map[string]interface{}) error { 104 bucket := tx.ReadBucket(rootKey) 105 if bucket == nil { 106 return fmt.Errorf("bucket %v not found", string(rootKey)) 107 } 108 109 return verifyDB(bucket, data) 110 } 111 112 func verifyDB(bucket kvdb.RBucket, data map[string]interface{}) error { 113 for k, v := range data { 114 key := []byte(k) 115 116 switch value := v.(type) { 117 118 // Key contains value. 119 case string: 120 expectedValue := []byte(value) 121 dbValue := bucket.Get(key) 122 123 if !bytes.Equal(dbValue, expectedValue) { 124 return errors.New("value mismatch") 125 } 126 127 // Key contains a sub-bucket. 128 case map[string]interface{}: 129 subBucket := bucket.NestedReadBucket(key) 130 if subBucket == nil { 131 return fmt.Errorf("bucket %v not found", k) 132 } 133 134 err := verifyDB(subBucket, value) 135 if err != nil { 136 return err 137 } 138 139 default: 140 return errors.New("invalid type") 141 } 142 } 143 144 keyCount := 0 145 err := bucket.ForEach(func(k, v []byte) error { 146 keyCount++ 147 return nil 148 }) 149 if err != nil { 150 return err 151 } 152 if keyCount != len(data) { 153 return errors.New("unexpected keys in database") 154 } 155 156 return nil 157 } 158 159 func toHex(v []byte) string { 160 if len(v) == 0 { 161 return "nil" 162 } 163 164 return "hex(\"" + hex.EncodeToString(v) + "\")" 165 } 166 167 func toString(v []byte) string { 168 readableChars := "abcdefghijklmnopqrstuvwxyz0123456789-" 169 170 for _, c := range v { 171 if !strings.Contains(readableChars, string(c)) { 172 return toHex(v) 173 } 174 } 175 176 return "\"" + string(v) + "\"" 177 } 178 179 // Hex is a test helper function to convert readable hex arrays to raw byte 180 // strings. 181 func Hex(value string) string { 182 b, err := hex.DecodeString(value) 183 if err != nil { 184 panic(err) 185 } 186 return string(b) 187 }