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.

304 lines
7.4 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  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. "github.com/tendermint/tendermint/types"
  11. )
  12. func makeStorage(db dbm.DB, root []byte) merkle.Tree {
  13. storage := merkle.NewIAVLTree(
  14. binary.BasicCodec,
  15. binary.BasicCodec,
  16. 1024,
  17. db,
  18. )
  19. storage.Load(root)
  20. return storage
  21. }
  22. type BlockCache struct {
  23. db dbm.DB
  24. backend *State
  25. accounts map[string]accountInfo
  26. storages map[Tuple256]storageInfo
  27. names map[string]nameInfo
  28. }
  29. func NewBlockCache(backend *State) *BlockCache {
  30. return &BlockCache{
  31. db: backend.DB,
  32. backend: backend,
  33. accounts: make(map[string]accountInfo),
  34. storages: make(map[Tuple256]storageInfo),
  35. names: make(map[string]nameInfo),
  36. }
  37. }
  38. func (cache *BlockCache) State() *State {
  39. return cache.backend
  40. }
  41. //-------------------------------------
  42. // BlockCache.account
  43. func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
  44. acc, _, removed, _ := cache.accounts[string(addr)].unpack()
  45. if removed {
  46. return nil
  47. } else if acc != nil {
  48. return acc
  49. } else {
  50. acc = cache.backend.GetAccount(addr)
  51. cache.accounts[string(addr)] = accountInfo{acc, nil, false, false}
  52. return acc
  53. }
  54. }
  55. func (cache *BlockCache) UpdateAccount(acc *ac.Account) {
  56. addr := acc.Address
  57. // SANITY CHECK
  58. _, storage, removed, _ := cache.accounts[string(addr)].unpack()
  59. if removed {
  60. panic("UpdateAccount on a removed account")
  61. }
  62. // SANITY CHECK END
  63. cache.accounts[string(addr)] = accountInfo{acc, storage, false, true}
  64. }
  65. func (cache *BlockCache) RemoveAccount(addr []byte) {
  66. // SANITY CHECK
  67. _, _, removed, _ := cache.accounts[string(addr)].unpack()
  68. if removed {
  69. panic("RemoveAccount on a removed account")
  70. }
  71. // SANITY CHECK END
  72. cache.accounts[string(addr)] = accountInfo{nil, nil, true, false}
  73. }
  74. // BlockCache.account
  75. //-------------------------------------
  76. // BlockCache.storage
  77. func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
  78. // Check cache
  79. info, ok := cache.storages[Tuple256{addr, key}]
  80. if ok {
  81. return info.value
  82. }
  83. // Get or load storage
  84. acc, storage, removed, dirty := cache.accounts[string(addr.Postfix(20))].unpack()
  85. if removed {
  86. panic("GetStorage() on removed account")
  87. }
  88. if acc != nil && storage == nil {
  89. storage = makeStorage(cache.db, acc.StorageRoot)
  90. cache.accounts[string(addr.Postfix(20))] = accountInfo{acc, storage, false, dirty}
  91. } else if acc == nil {
  92. return Zero256
  93. }
  94. // Load and set cache
  95. _, val_ := storage.Get(key.Bytes())
  96. value = Zero256
  97. if val_ != nil {
  98. value = LeftPadWord256(val_.([]byte))
  99. }
  100. cache.storages[Tuple256{addr, key}] = storageInfo{value, false}
  101. return value
  102. }
  103. // NOTE: Set value to zero to removed from the trie.
  104. func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) {
  105. _, _, removed, _ := cache.accounts[string(addr.Postfix(20))].unpack()
  106. if removed {
  107. panic("SetStorage() on a removed account")
  108. }
  109. cache.storages[Tuple256{addr, key}] = storageInfo{value, true}
  110. }
  111. // BlockCache.storage
  112. //-------------------------------------
  113. // BlockCache.names
  114. func (cache *BlockCache) GetNameRegEntry(name string) *types.NameRegEntry {
  115. entry, removed, _ := cache.names[name].unpack()
  116. if removed {
  117. return nil
  118. } else if entry != nil {
  119. return entry
  120. } else {
  121. entry = cache.backend.GetNameRegEntry(name)
  122. cache.names[name] = nameInfo{entry, false, false}
  123. return entry
  124. }
  125. }
  126. func (cache *BlockCache) UpdateNameRegEntry(entry *types.NameRegEntry) {
  127. name := entry.Name
  128. // SANITY CHECK
  129. _, removed, _ := cache.names[name].unpack()
  130. if removed {
  131. panic("UpdateNameRegEntry on a removed name")
  132. }
  133. // SANITY CHECK END
  134. cache.names[name] = nameInfo{entry, false, true}
  135. }
  136. func (cache *BlockCache) RemoveNameRegEntry(name string) {
  137. // SANITY CHECK
  138. _, removed, _ := cache.names[name].unpack()
  139. if removed {
  140. panic("RemoveNameRegEntry on a removed entry")
  141. }
  142. // SANITY CHECK END
  143. cache.names[name] = nameInfo{nil, true, false}
  144. }
  145. // BlockCache.names
  146. //-------------------------------------
  147. // CONTRACT the updates are in deterministic order.
  148. func (cache *BlockCache) Sync() {
  149. // Determine order for storage updates
  150. // The address comes first so it'll be grouped.
  151. storageKeys := make([]Tuple256, 0, len(cache.storages))
  152. for keyTuple := range cache.storages {
  153. storageKeys = append(storageKeys, keyTuple)
  154. }
  155. Tuple256Slice(storageKeys).Sort()
  156. // Update storage for all account/key.
  157. // Later we'll iterate over all the users and save storage + update storage root.
  158. var (
  159. curAddr Word256
  160. curAcc *ac.Account
  161. curAccRemoved bool
  162. curStorage merkle.Tree
  163. )
  164. for _, storageKey := range storageKeys {
  165. addr, key := Tuple256Split(storageKey)
  166. if addr != curAddr || curAcc == nil {
  167. acc, storage, removed, _ := cache.accounts[string(addr.Postfix(20))].unpack()
  168. if storage == nil {
  169. storage = makeStorage(cache.db, acc.StorageRoot)
  170. }
  171. curAddr = addr
  172. curAcc = acc
  173. curAccRemoved = removed
  174. curStorage = storage
  175. }
  176. if curAccRemoved {
  177. continue
  178. }
  179. value, dirty := cache.storages[storageKey].unpack()
  180. if !dirty {
  181. continue
  182. }
  183. if value.IsZero() {
  184. curStorage.Remove(key.Bytes())
  185. } else {
  186. curStorage.Set(key.Bytes(), value.Bytes())
  187. cache.accounts[string(addr.Postfix(20))] = accountInfo{curAcc, curStorage, false, true}
  188. }
  189. }
  190. // Determine order for accounts
  191. addrStrs := []string{}
  192. for addrStr := range cache.accounts {
  193. addrStrs = append(addrStrs, addrStr)
  194. }
  195. sort.Strings(addrStrs)
  196. // Update or delete accounts.
  197. for _, addrStr := range addrStrs {
  198. acc, storage, removed, dirty := cache.accounts[addrStr].unpack()
  199. if removed {
  200. removed := cache.backend.RemoveAccount(acc.Address)
  201. if !removed {
  202. panic(Fmt("Could not remove account to be removed: %X", acc.Address))
  203. }
  204. } else {
  205. if acc == nil {
  206. continue
  207. }
  208. if storage != nil {
  209. newStorageRoot := storage.Save()
  210. if !bytes.Equal(newStorageRoot, acc.StorageRoot) {
  211. acc.StorageRoot = newStorageRoot
  212. dirty = true
  213. }
  214. }
  215. if dirty {
  216. cache.backend.UpdateAccount(acc)
  217. }
  218. }
  219. }
  220. // Determine order for names
  221. // note names may be of any length less than some limit
  222. nameStrs := []string{}
  223. for nameStr := range cache.names {
  224. nameStrs = append(nameStrs, nameStr)
  225. }
  226. sort.Strings(nameStrs)
  227. // Update or delete names.
  228. for _, nameStr := range nameStrs {
  229. entry, removed, dirty := cache.names[nameStr].unpack()
  230. if removed {
  231. removed := cache.backend.RemoveNameRegEntry(nameStr)
  232. if !removed {
  233. panic(Fmt("Could not remove namereg entry to be removed: %s", nameStr))
  234. }
  235. } else {
  236. if entry == nil {
  237. continue
  238. }
  239. if dirty {
  240. cache.backend.UpdateNameRegEntry(entry)
  241. }
  242. }
  243. }
  244. }
  245. //-----------------------------------------------------------------------------
  246. type accountInfo struct {
  247. account *ac.Account
  248. storage merkle.Tree
  249. removed bool
  250. dirty bool
  251. }
  252. func (accInfo accountInfo) unpack() (*ac.Account, merkle.Tree, bool, bool) {
  253. return accInfo.account, accInfo.storage, accInfo.removed, accInfo.dirty
  254. }
  255. type storageInfo struct {
  256. value Word256
  257. dirty bool
  258. }
  259. func (stjInfo storageInfo) unpack() (Word256, bool) {
  260. return stjInfo.value, stjInfo.dirty
  261. }
  262. type nameInfo struct {
  263. name *types.NameRegEntry
  264. removed bool
  265. dirty bool
  266. }
  267. func (nInfo nameInfo) unpack() (*types.NameRegEntry, bool, bool) {
  268. return nInfo.name, nInfo.removed, nInfo.dirty
  269. }