You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
8.9 KiB

  1. // Package keymigrate translates all legacy formatted keys to their
  2. // new components.
  3. //
  4. // The key migration operation as implemented provides a potential
  5. // model for database migration operations. Crucially, the migration
  6. // as implemented does not depend on any tendermint code.
  7. package keymigrate
  8. import (
  9. "bytes"
  10. "context"
  11. "encoding/binary"
  12. "encoding/hex"
  13. "fmt"
  14. "math/rand"
  15. "runtime"
  16. "strconv"
  17. "sync"
  18. "github.com/google/orderedcode"
  19. "github.com/pkg/errors"
  20. dbm "github.com/tendermint/tm-db"
  21. )
  22. type (
  23. keyID []byte
  24. migrateFunc func(keyID) (keyID, error)
  25. )
  26. func getAllLegacyKeys(db dbm.DB) ([]keyID, error) {
  27. out := []keyID{}
  28. iter, err := db.Iterator(nil, nil)
  29. if err != nil {
  30. return nil, err
  31. }
  32. for ; iter.Valid(); iter.Next() {
  33. k := iter.Key()
  34. // make sure it's a key with a legacy format, and skip
  35. // all other keys, to make it safe to resume the migration.
  36. if !keyIsLegacy(k) {
  37. continue
  38. }
  39. // there's inconsistency around tm-db's handling of
  40. // key copies.
  41. nk := make([]byte, len(k))
  42. copy(nk, k)
  43. out = append(out, nk)
  44. }
  45. if err = iter.Error(); err != nil {
  46. return nil, err
  47. }
  48. if err = iter.Close(); err != nil {
  49. return nil, err
  50. }
  51. return out, nil
  52. }
  53. func makeKeyChan(keys []keyID) <-chan keyID {
  54. out := make(chan keyID, len(keys))
  55. defer close(out)
  56. for _, key := range keys {
  57. out <- key
  58. }
  59. return out
  60. }
  61. func keyIsLegacy(key keyID) bool {
  62. for _, prefix := range []keyID{
  63. // core "store"
  64. keyID("consensusParamsKey:"),
  65. keyID("abciResponsesKey:"),
  66. keyID("validatorsKey:"),
  67. keyID("stateKey"),
  68. keyID("H:"),
  69. keyID("P:"),
  70. keyID("C:"),
  71. keyID("SC:"),
  72. keyID("BH:"),
  73. // light
  74. keyID("size"),
  75. keyID("lb/"),
  76. // evidence
  77. keyID([]byte{0x00}),
  78. keyID([]byte{0x01}),
  79. // tx index
  80. keyID("tx.height/"),
  81. keyID("tx.hash/"),
  82. } {
  83. if bytes.HasPrefix(key, prefix) {
  84. return true
  85. }
  86. }
  87. // this means it's a tx index...
  88. if bytes.Count(key, []byte("/")) >= 3 {
  89. return true
  90. }
  91. return keyIsHash(key)
  92. }
  93. func keyIsHash(key keyID) bool {
  94. return len(key) == 32 && !bytes.Contains(key, []byte("/"))
  95. }
  96. func migarateKey(key keyID) (keyID, error) {
  97. switch {
  98. case bytes.HasPrefix(key, keyID("H:")):
  99. val, err := strconv.Atoi(string(key[2:]))
  100. if err != nil {
  101. return nil, err
  102. }
  103. return orderedcode.Append(nil, int64(0), int64(val))
  104. case bytes.HasPrefix(key, keyID("P:")):
  105. parts := bytes.Split(key[2:], []byte(":"))
  106. if len(parts) != 2 {
  107. return nil, fmt.Errorf("block parts key has %d rather than 2 components",
  108. len(parts))
  109. }
  110. valOne, err := strconv.Atoi(string(parts[0]))
  111. if err != nil {
  112. return nil, err
  113. }
  114. valTwo, err := strconv.Atoi(string(parts[1]))
  115. if err != nil {
  116. return nil, err
  117. }
  118. return orderedcode.Append(nil, int64(1), int64(valOne), int64(valTwo))
  119. case bytes.HasPrefix(key, keyID("C:")):
  120. val, err := strconv.Atoi(string(key[2:]))
  121. if err != nil {
  122. return nil, err
  123. }
  124. return orderedcode.Append(nil, int64(2), int64(val))
  125. case bytes.HasPrefix(key, keyID("SC:")):
  126. val, err := strconv.Atoi(string(key[3:]))
  127. if err != nil {
  128. return nil, err
  129. }
  130. return orderedcode.Append(nil, int64(3), int64(val))
  131. case bytes.HasPrefix(key, keyID("BH:")):
  132. val, err := strconv.Atoi(string(key[3:]))
  133. if err != nil {
  134. return nil, err
  135. }
  136. return orderedcode.Append(nil, int64(4), int64(val))
  137. case bytes.HasPrefix(key, keyID("validatorsKey:")):
  138. val, err := strconv.Atoi(string(key[14:]))
  139. if err != nil {
  140. return nil, err
  141. }
  142. return orderedcode.Append(nil, int64(5), int64(val))
  143. case bytes.HasPrefix(key, keyID("consensusParamsKey:")):
  144. val, err := strconv.Atoi(string(key[19:]))
  145. if err != nil {
  146. return nil, err
  147. }
  148. return orderedcode.Append(nil, int64(6), int64(val))
  149. case bytes.HasPrefix(key, keyID("abciResponsesKey:")):
  150. val, err := strconv.Atoi(string(key[17:]))
  151. if err != nil {
  152. return nil, err
  153. }
  154. return orderedcode.Append(nil, int64(7), int64(val))
  155. case bytes.HasPrefix(key, keyID("stateKey")):
  156. return orderedcode.Append(nil, int64(8))
  157. case bytes.HasPrefix(key, []byte{0x00}): // committed evidence
  158. return convertEvidence(key, 9)
  159. case bytes.HasPrefix(key, []byte{0x01}): // pending evidence
  160. return convertEvidence(key, 10)
  161. case bytes.HasPrefix(key, keyID("lb/")):
  162. if len(key) < 24 {
  163. return nil, fmt.Errorf("light block evidence %q in invalid format", string(key))
  164. }
  165. val, err := strconv.Atoi(string(key[len(key)-20:]))
  166. if err != nil {
  167. return nil, err
  168. }
  169. return orderedcode.Append(nil, int64(11), int64(val))
  170. case bytes.HasPrefix(key, keyID("size")):
  171. return orderedcode.Append(nil, int64(12))
  172. case bytes.HasPrefix(key, keyID("tx.height")):
  173. parts := bytes.Split(key, []byte("/"))
  174. if len(parts) != 4 {
  175. return nil, fmt.Errorf("key has %d parts rather than 4", len(parts))
  176. }
  177. parts = parts[1:] // drop prefix
  178. elems := make([]interface{}, 0, len(parts)+1)
  179. elems = append(elems, "tx.height")
  180. for idx, pt := range parts {
  181. val, err := strconv.Atoi(string(pt))
  182. if err != nil {
  183. return nil, err
  184. }
  185. if idx == 0 {
  186. elems = append(elems, fmt.Sprintf("%d", val))
  187. } else {
  188. elems = append(elems, int64(val))
  189. }
  190. }
  191. return orderedcode.Append(nil, elems...)
  192. case bytes.Count(key, []byte("/")) >= 3: // tx indexer
  193. parts := bytes.Split(key, []byte("/"))
  194. elems := make([]interface{}, 0, 4)
  195. if len(parts) == 4 {
  196. elems = append(elems, string(parts[0]), string(parts[1]))
  197. val, err := strconv.Atoi(string(parts[2]))
  198. if err != nil {
  199. return nil, err
  200. }
  201. elems = append(elems, int64(val))
  202. val2, err := strconv.Atoi(string(parts[3]))
  203. if err != nil {
  204. return nil, err
  205. }
  206. elems = append(elems, int64(val2))
  207. } else {
  208. elems = append(elems, string(parts[0]))
  209. parts = parts[1:]
  210. val, err := strconv.Atoi(string(parts[len(parts)-1]))
  211. if err != nil {
  212. return nil, err
  213. }
  214. val2, err := strconv.Atoi(string(parts[len(parts)-2]))
  215. if err != nil {
  216. return nil, err
  217. }
  218. appKey := bytes.Join(parts[:len(parts)-3], []byte("/"))
  219. elems = append(elems, string(appKey), int64(val), int64(val2))
  220. }
  221. return orderedcode.Append(nil, elems...)
  222. case keyIsHash(key):
  223. return orderedcode.Append(nil, "tx.hash", string(key))
  224. default:
  225. return nil, fmt.Errorf("key %q is in the wrong format", string(key))
  226. }
  227. }
  228. func convertEvidence(key keyID, newPrefix int64) ([]byte, error) {
  229. parts := bytes.Split(key[1:], []byte("/"))
  230. if len(parts) != 2 {
  231. return nil, fmt.Errorf("evidence key is malformed with %d parts not 2",
  232. len(parts))
  233. }
  234. hb, err := hex.DecodeString(string(parts[0]))
  235. if err != nil {
  236. return nil, err
  237. }
  238. evidenceHash, err := hex.DecodeString(string(parts[1]))
  239. if err != nil {
  240. return nil, err
  241. }
  242. return orderedcode.Append(nil, newPrefix, binary.BigEndian.Uint64(hb), string(evidenceHash))
  243. }
  244. func replaceKey(db dbm.DB, key keyID, gooseFn migrateFunc) error {
  245. exists, err := db.Has(key)
  246. if err != nil {
  247. return err
  248. }
  249. if !exists {
  250. return nil
  251. }
  252. newKey, err := gooseFn(key)
  253. if err != nil {
  254. return err
  255. }
  256. val, err := db.Get(key)
  257. if err != nil {
  258. return err
  259. }
  260. batch := db.NewBatch()
  261. if err = batch.Set(newKey, val); err != nil {
  262. return err
  263. }
  264. if err = batch.Delete(key); err != nil {
  265. return err
  266. }
  267. // 10% of the time, force a write to disk, but mostly don't,
  268. // because it's faster.
  269. if rand.Intn(100)%10 == 0 { // nolint:gosec
  270. if err = batch.WriteSync(); err != nil {
  271. return err
  272. }
  273. } else {
  274. if err = batch.Write(); err != nil {
  275. return err
  276. }
  277. }
  278. if err = batch.Close(); err != nil {
  279. return err
  280. }
  281. return nil
  282. }
  283. // Migrate converts all legacy key formats to new key formats. The
  284. // operation is idempotent, so it's safe to resume a failed
  285. // operation. The operation is somewhat parallelized, relying on the
  286. // concurrency safety of the underlying databases.
  287. //
  288. // Migrate has "continue on error" semantics and will iterate through
  289. // all legacy keys attempt to migrate them, and will collect all
  290. // errors and will return only at the end of the operation.
  291. //
  292. // The context allows for a safe termination of the operation
  293. // (e.g connected to a singal handler,) to abort the operation
  294. // in-between migration operations.
  295. func Migrate(ctx context.Context, db dbm.DB) error {
  296. keys, err := getAllLegacyKeys(db)
  297. if err != nil {
  298. return err
  299. }
  300. numWorkers := runtime.NumCPU()
  301. wg := &sync.WaitGroup{}
  302. errs := make(chan error, numWorkers)
  303. keyCh := makeKeyChan(keys)
  304. // run migrations.
  305. for i := 0; i < numWorkers; i++ {
  306. wg.Add(1)
  307. go func() {
  308. defer wg.Done()
  309. for key := range keyCh {
  310. err := replaceKey(db, key, migarateKey)
  311. if err != nil {
  312. errs <- err
  313. }
  314. if ctx.Err() != nil {
  315. return
  316. }
  317. }
  318. }()
  319. }
  320. // collect and process the errors.
  321. errStrs := []string{}
  322. signal := make(chan struct{})
  323. go func() {
  324. defer close(signal)
  325. for err := range errs {
  326. if err == nil {
  327. continue
  328. }
  329. errStrs = append(errStrs, err.Error())
  330. }
  331. }()
  332. // Wait for everything to be done.
  333. wg.Wait()
  334. close(errs)
  335. <-signal
  336. // check the error results
  337. if len(errs) != 0 {
  338. return errors.Errorf("encountered errors during migration: %v", errStrs)
  339. }
  340. return nil
  341. }