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.

227 lines
5.6 KiB

  1. package state
  2. import (
  3. "bytes"
  4. "sort"
  5. ac "github.com/tendermint/tendermint/account"
  6. "github.com/tendermint/tendermint/binary"
  7. . "github.com/tendermint/tendermint/common"
  8. dbm "github.com/tendermint/tendermint/db"
  9. "github.com/tendermint/tendermint/merkle"
  10. )
  11. func makeStorage(db dbm.DB, root []byte) merkle.Tree {
  12. storage := merkle.NewIAVLTree(
  13. binary.BasicCodec,
  14. binary.BasicCodec,
  15. 1024,
  16. db,
  17. )
  18. storage.Load(root)
  19. return storage
  20. }
  21. type BlockCache struct {
  22. db dbm.DB
  23. backend *State
  24. accounts map[string]accountInfo
  25. storages map[Tuple256]storageInfo
  26. }
  27. func NewBlockCache(backend *State) *BlockCache {
  28. return &BlockCache{
  29. db: backend.DB,
  30. backend: backend,
  31. accounts: make(map[string]accountInfo),
  32. storages: make(map[Tuple256]storageInfo),
  33. }
  34. }
  35. func (cache *BlockCache) State() *State {
  36. return cache.backend
  37. }
  38. //-------------------------------------
  39. // BlockCache.account
  40. func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
  41. acc, _, removed, _ := cache.accounts[string(addr)].unpack()
  42. if removed {
  43. return nil
  44. } else if acc != nil {
  45. return acc
  46. } else {
  47. acc = cache.backend.GetAccount(addr)
  48. cache.accounts[string(addr)] = accountInfo{acc, nil, false, false}
  49. return acc
  50. }
  51. }
  52. func (cache *BlockCache) UpdateAccount(acc *ac.Account) {
  53. addr := acc.Address
  54. // SANITY CHECK
  55. _, storage, removed, _ := cache.accounts[string(addr)].unpack()
  56. if removed {
  57. panic("UpdateAccount on a removed account")
  58. }
  59. // SANITY CHECK END
  60. cache.accounts[string(addr)] = accountInfo{acc, storage, false, true}
  61. }
  62. func (cache *BlockCache) RemoveAccount(addr []byte) {
  63. // SANITY CHECK
  64. _, _, removed, _ := cache.accounts[string(addr)].unpack()
  65. if removed {
  66. panic("RemoveAccount on a removed account")
  67. }
  68. // SANITY CHECK END
  69. cache.accounts[string(addr)] = accountInfo{nil, nil, true, false}
  70. }
  71. // BlockCache.account
  72. //-------------------------------------
  73. // BlockCache.storage
  74. func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
  75. // Check cache
  76. info, ok := cache.storages[Tuple256{addr, key}]
  77. if ok {
  78. return info.value
  79. }
  80. // Get or load storage
  81. acc, storage, removed, dirty := cache.accounts[string(addr.Prefix(20))].unpack()
  82. if removed {
  83. panic("GetStorage() on removed account")
  84. }
  85. if acc != nil && storage == nil {
  86. storage = makeStorage(cache.db, acc.StorageRoot)
  87. cache.accounts[string(addr.Prefix(20))] = accountInfo{acc, storage, false, dirty}
  88. } else if acc == nil {
  89. return Zero256
  90. }
  91. // Load and set cache
  92. _, val_ := storage.Get(key.Bytes())
  93. value = Zero256
  94. if val_ != nil {
  95. value = RightPadWord256(val_.([]byte))
  96. }
  97. cache.storages[Tuple256{addr, key}] = storageInfo{value, false}
  98. return value
  99. }
  100. // NOTE: Set value to zero to removed from the trie.
  101. func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) {
  102. _, _, removed, _ := cache.accounts[string(addr.Prefix(20))].unpack()
  103. if removed {
  104. panic("SetStorage() on a removed account")
  105. }
  106. cache.storages[Tuple256{addr, key}] = storageInfo{value, true}
  107. }
  108. // BlockCache.storage
  109. //-------------------------------------
  110. // CONTRACT the updates are in deterministic order.
  111. func (cache *BlockCache) Sync() {
  112. // Determine order for storage updates
  113. // The address comes first so it'll be grouped.
  114. storageKeys := make([]Tuple256, 0, len(cache.storages))
  115. for keyTuple := range cache.storages {
  116. storageKeys = append(storageKeys, keyTuple)
  117. }
  118. Tuple256Slice(storageKeys).Sort()
  119. // Update storage for all account/key.
  120. // Later we'll iterate over all the users and save storage + update storage root.
  121. var (
  122. curAddr Word256
  123. curAcc *ac.Account
  124. curAccRemoved bool
  125. curStorage merkle.Tree
  126. )
  127. for _, storageKey := range storageKeys {
  128. addr, key := Tuple256Split(storageKey)
  129. if addr != curAddr || curAcc == nil {
  130. acc, storage, removed, _ := cache.accounts[string(addr.Prefix(20))].unpack()
  131. if storage == nil {
  132. storage = makeStorage(cache.db, acc.StorageRoot)
  133. }
  134. curAddr = addr
  135. curAcc = acc
  136. curAccRemoved = removed
  137. curStorage = storage
  138. }
  139. if curAccRemoved {
  140. continue
  141. }
  142. value, dirty := cache.storages[storageKey].unpack()
  143. if !dirty {
  144. continue
  145. }
  146. if value.IsZero() {
  147. curStorage.Remove(key.Bytes())
  148. } else {
  149. curStorage.Set(key.Bytes(), value.Bytes())
  150. cache.accounts[string(addr.Prefix(20))] = accountInfo{curAcc, curStorage, false, true}
  151. }
  152. }
  153. // Determine order for accounts
  154. addrStrs := []string{}
  155. for addrStr := range cache.accounts {
  156. addrStrs = append(addrStrs, addrStr)
  157. }
  158. sort.Strings(addrStrs)
  159. // Update or delete accounts.
  160. for _, addrStr := range addrStrs {
  161. acc, storage, removed, dirty := cache.accounts[addrStr].unpack()
  162. if removed {
  163. removed := cache.backend.RemoveAccount(acc.Address)
  164. if !removed {
  165. panic(Fmt("Could not remove account to be removed: %X", acc.Address))
  166. }
  167. } else {
  168. if acc == nil {
  169. panic(Fmt("Account should not be nil for addr: %X", acc.Address))
  170. }
  171. if storage != nil {
  172. newStorageRoot := storage.Save()
  173. if !bytes.Equal(newStorageRoot, acc.StorageRoot) {
  174. acc.StorageRoot = newStorageRoot
  175. dirty = true
  176. }
  177. }
  178. if dirty {
  179. cache.backend.UpdateAccount(acc)
  180. }
  181. }
  182. }
  183. }
  184. //-----------------------------------------------------------------------------
  185. type accountInfo struct {
  186. account *ac.Account
  187. storage merkle.Tree
  188. removed bool
  189. dirty bool
  190. }
  191. func (accInfo accountInfo) unpack() (*ac.Account, merkle.Tree, bool, bool) {
  192. return accInfo.account, accInfo.storage, accInfo.removed, accInfo.dirty
  193. }
  194. type storageInfo struct {
  195. value Word256
  196. dirty bool
  197. }
  198. func (stjInfo storageInfo) unpack() (Word256, bool) {
  199. return stjInfo.value, stjInfo.dirty
  200. }