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.

178 lines
4.8 KiB

  1. /**
  2. * @file
  3. * @copyright defined in aergo/LICENSE.txt
  4. */
  5. package trie
  6. import (
  7. "bytes"
  8. "fmt"
  9. )
  10. // Revert rewinds the state tree to a previous version
  11. // All the nodes (subtree roots and values) reverted are deleted from the database.
  12. func (s *Trie) Revert(toOldRoot []byte) error {
  13. s.lock.RLock()
  14. defer s.lock.RUnlock()
  15. // safety precaution if reverting to a shortcut batch that might have been deleted
  16. s.atomicUpdate = false // so loadChildren doesnt return a copy
  17. batch, _, _, _, isShortcut, err := s.loadChildren(toOldRoot, s.TrieHeight, 0, nil)
  18. if err != nil {
  19. return err
  20. }
  21. //check if toOldRoot is in s.pastTries
  22. canRevert := false
  23. toIndex := 0
  24. for i, r := range s.pastTries {
  25. if bytes.Equal(r, toOldRoot) {
  26. canRevert = true
  27. toIndex = i
  28. break
  29. }
  30. }
  31. if !canRevert || bytes.Equal(s.Root, toOldRoot) {
  32. return fmt.Errorf("The root cannot be reverted, because already latest of not in pastTries : current : %x, target : %x", s.Root, toOldRoot)
  33. }
  34. // For every node of toOldRoot, compare it to the equivalent node in other pasttries between toOldRoot and current s.Root. If a node is different, delete the one from pasttries
  35. s.db.nodesToRevert = make([][]byte, 0)
  36. for i := toIndex + 1; i < len(s.pastTries); i++ {
  37. ch := make(chan error, 1)
  38. s.maybeDeleteSubTree(toOldRoot, s.pastTries[i], s.TrieHeight, 0, nil, nil, ch)
  39. err := <-ch
  40. if err != nil {
  41. return err
  42. }
  43. }
  44. // NOTE The tx interface doesnt handle ErrTxnTooBig
  45. txn := s.db.Store.NewTx()
  46. for _, key := range s.db.nodesToRevert {
  47. txn.Delete(key[:HashLength])
  48. }
  49. txn.Commit()
  50. s.pastTries = s.pastTries[:toIndex+1]
  51. s.Root = toOldRoot
  52. s.db.liveCache = make(map[Hash][][]byte)
  53. s.db.updatedNodes = make(map[Hash][][]byte)
  54. if isShortcut {
  55. // If toOldRoot is a shortcut batch, it is possible that
  56. // revert has deleted it if the key was ever stored at height0
  57. // because in leafHash byte(0) = byte(256)
  58. s.db.Store.Set(toOldRoot, s.db.serializeBatch(batch))
  59. }
  60. return nil
  61. }
  62. // maybeDeleteSubTree compares the subtree nodes of 2 tries and keeps only the older one
  63. func (s *Trie) maybeDeleteSubTree(original, maybeDelete []byte, height, iBatch int, batch, batch2 [][]byte, ch chan<- (error)) {
  64. if height == 0 {
  65. if !bytes.Equal(original, maybeDelete) && len(maybeDelete) != 0 {
  66. s.maybeDeleteRevertedNode(maybeDelete, 0)
  67. }
  68. ch <- nil
  69. return
  70. }
  71. if bytes.Equal(original, maybeDelete) || len(maybeDelete) == 0 {
  72. ch <- nil
  73. return
  74. }
  75. // if this point os reached, then the root of the batch is same
  76. // so the batch is also same.
  77. batch, iBatch, lnode, rnode, isShortcut, lerr := s.loadChildren(original, height, iBatch, batch)
  78. if lerr != nil {
  79. ch <- lerr
  80. return
  81. }
  82. batch2, _, lnode2, rnode2, isShortcut2, rerr := s.loadChildren(maybeDelete, height, iBatch, batch2)
  83. if rerr != nil {
  84. ch <- rerr
  85. return
  86. }
  87. if isShortcut != isShortcut2 {
  88. if isShortcut {
  89. ch1 := make(chan error, 1)
  90. s.deleteSubTree(maybeDelete, height, iBatch, batch2, ch1)
  91. err := <-ch1
  92. if err != nil {
  93. ch <- err
  94. return
  95. }
  96. } else {
  97. s.maybeDeleteRevertedNode(maybeDelete, iBatch)
  98. }
  99. } else {
  100. if isShortcut {
  101. // Delete shortcut if not equal
  102. if !bytes.Equal(lnode, lnode2) || !bytes.Equal(rnode, rnode2) {
  103. s.maybeDeleteRevertedNode(maybeDelete, iBatch)
  104. }
  105. } else {
  106. // Delete subtree if not equal
  107. s.maybeDeleteRevertedNode(maybeDelete, iBatch)
  108. ch1 := make(chan error, 1)
  109. ch2 := make(chan error, 1)
  110. go s.maybeDeleteSubTree(lnode, lnode2, height-1, 2*iBatch+1, batch, batch2, ch1)
  111. go s.maybeDeleteSubTree(rnode, rnode2, height-1, 2*iBatch+2, batch, batch2, ch2)
  112. err1, err2 := <-ch1, <-ch2
  113. if err1 != nil {
  114. ch <- err1
  115. return
  116. }
  117. if err2 != nil {
  118. ch <- err2
  119. return
  120. }
  121. }
  122. }
  123. ch <- nil
  124. }
  125. // deleteSubTree deletes all the nodes contained in a tree
  126. func (s *Trie) deleteSubTree(root []byte, height, iBatch int, batch [][]byte, ch chan<- (error)) {
  127. if len(root) == 0 || height == 0 {
  128. if height == 0 {
  129. s.maybeDeleteRevertedNode(root, 0)
  130. }
  131. ch <- nil
  132. return
  133. }
  134. batch, iBatch, lnode, rnode, isShortcut, err := s.loadChildren(root, height, iBatch, batch)
  135. if err != nil {
  136. ch <- err
  137. return
  138. }
  139. if !isShortcut {
  140. ch1 := make(chan error, 1)
  141. ch2 := make(chan error, 1)
  142. go s.deleteSubTree(lnode, height-1, 2*iBatch+1, batch, ch1)
  143. go s.deleteSubTree(rnode, height-1, 2*iBatch+2, batch, ch2)
  144. lerr := <-ch1
  145. rerr := <-ch2
  146. if lerr != nil {
  147. ch <- lerr
  148. return
  149. }
  150. if rerr != nil {
  151. ch <- rerr
  152. return
  153. }
  154. }
  155. s.maybeDeleteRevertedNode(root, iBatch)
  156. ch <- nil
  157. }
  158. // maybeDeleteRevertedNode adds the node to updatedNodes to be reverted
  159. // if it is a batch node at height%4 == 0
  160. func (s *Trie) maybeDeleteRevertedNode(root []byte, iBatch int) {
  161. if iBatch == 0 {
  162. s.db.revertMux.Lock()
  163. s.db.nodesToRevert = append(s.db.nodesToRevert, root)
  164. s.db.revertMux.Unlock()
  165. }
  166. }