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
  1. package state
  2. import (
  3. "bytes"
  4. "sort"
  5. acm "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) *acm.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 *acm.Account) {
  56. addr := acc.Address
  57. _, storage, removed, _ := cache.accounts[string(addr)].unpack()
  58. // SANITY CHECK
  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. // SANITY CHECK
  86. if removed {
  87. panic("GetStorage() on removed account")
  88. }
  89. // SANITY CHECK END
  90. if acc != nil && storage == nil {
  91. storage = makeStorage(cache.db, acc.StorageRoot)
  92. cache.accounts[string(addr.Postfix(20))] = accountInfo{acc, storage, false, dirty}
  93. } else if acc == nil {
  94. return Zero256
  95. }
  96. // Load and set cache
  97. _, val_ := storage.Get(key.Bytes())
  98. value = Zero256
  99. if val_ != nil {
  100. value = LeftPadWord256(val_.([]byte))
  101. }
  102. cache.storages[Tuple256{addr, key}] = storageInfo{value, false}
  103. return value
  104. }
  105. // NOTE: Set value to zero to removed from the trie.
  106. func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) {
  107. // SANITY CHECK
  108. _, _, removed, _ := cache.accounts[string(addr.Postfix(20))].unpack()
  109. if removed {
  110. panic("SetStorage() on a removed account")
  111. }
  112. // SANITY CHECK END
  113. cache.storages[Tuple256{addr, key}] = storageInfo{value, true}
  114. }
  115. // BlockCache.storage
  116. //-------------------------------------
  117. // BlockCache.names
  118. func (cache *BlockCache) GetNameRegEntry(name string) *types.NameRegEntry {
  119. entry, removed, _ := cache.names[name].unpack()
  120. if removed {
  121. return nil
  122. } else if entry != nil {
  123. return entry
  124. } else {
  125. entry = cache.backend.GetNameRegEntry(name)
  126. cache.names[name] = nameInfo{entry, false, false}
  127. return entry
  128. }
  129. }
  130. func (cache *BlockCache) UpdateNameRegEntry(entry *types.NameRegEntry) {
  131. name := entry.Name
  132. cache.names[name] = nameInfo{entry, false, true}
  133. }
  134. func (cache *BlockCache) RemoveNameRegEntry(name string) {
  135. // SANITY CHECK
  136. _, removed, _ := cache.names[name].unpack()
  137. if removed {
  138. panic("RemoveNameRegEntry on a removed entry")
  139. }
  140. // SANITY CHECK END
  141. cache.names[name] = nameInfo{nil, true, false}
  142. }
  143. // BlockCache.names
  144. //-------------------------------------
  145. // CONTRACT the updates are in deterministic order.
  146. func (cache *BlockCache) Sync() {
  147. // Determine order for storage updates
  148. // The address comes first so it'll be grouped.
  149. storageKeys := make([]Tuple256, 0, len(cache.storages))
  150. for keyTuple := range cache.storages {
  151. storageKeys = append(storageKeys, keyTuple)
  152. }
  153. Tuple256Slice(storageKeys).Sort()
  154. // Update storage for all account/key.
  155. // Later we'll iterate over all the users and save storage + update storage root.
  156. var (
  157. curAddr Word256
  158. curAcc *acm.Account
  159. curAccRemoved bool
  160. curStorage merkle.Tree
  161. )
  162. for _, storageKey := range storageKeys {
  163. addr, key := Tuple256Split(storageKey)
  164. if addr != curAddr || curAcc == nil {
  165. acc, storage, removed, _ := cache.accounts[string(addr.Postfix(20))].unpack()
  166. if storage == nil {
  167. storage = makeStorage(cache.db, acc.StorageRoot)
  168. }
  169. curAddr = addr
  170. curAcc = acc
  171. curAccRemoved = removed
  172. curStorage = storage
  173. }
  174. if curAccRemoved {
  175. continue
  176. }
  177. value, dirty := cache.storages[storageKey].unpack()
  178. if !dirty {
  179. continue
  180. }
  181. if value.IsZero() {
  182. curStorage.Remove(key.Bytes())
  183. } else {
  184. curStorage.Set(key.Bytes(), value.Bytes())
  185. cache.accounts[string(addr.Postfix(20))] = accountInfo{curAcc, curStorage, false, true}
  186. }
  187. }
  188. // Determine order for accounts
  189. addrStrs := []string{}
  190. for addrStr := range cache.accounts {
  191. addrStrs = append(addrStrs, addrStr)
  192. }
  193. sort.Strings(addrStrs)
  194. // Update or delete accounts.
  195. for _, addrStr := range addrStrs {
  196. acc, storage, removed, dirty := cache.accounts[addrStr].unpack()
  197. if removed {
  198. removed := cache.backend.RemoveAccount(acc.Address)
  199. if !removed {
  200. // SOMETHING HORRIBLE HAS GONE WRONG
  201. panic(Fmt("Could not remove account to be removed: %X", acc.Address))
  202. }
  203. } else {
  204. if acc == nil {
  205. continue
  206. }
  207. if storage != nil {
  208. newStorageRoot := storage.Save()
  209. if !bytes.Equal(newStorageRoot, acc.StorageRoot) {
  210. acc.StorageRoot = newStorageRoot
  211. dirty = true
  212. }
  213. }
  214. if dirty {
  215. cache.backend.UpdateAccount(acc)
  216. }
  217. }
  218. }
  219. // Determine order for names
  220. // note names may be of any length less than some limit
  221. nameStrs := []string{}
  222. for nameStr := range cache.names {
  223. nameStrs = append(nameStrs, nameStr)
  224. }
  225. sort.Strings(nameStrs)
  226. // Update or delete names.
  227. for _, nameStr := range nameStrs {
  228. entry, removed, dirty := cache.names[nameStr].unpack()
  229. if removed {
  230. removed := cache.backend.RemoveNameRegEntry(nameStr)
  231. if !removed {
  232. // SOMETHING HORRIBLE HAS GONE WRONG
  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 *acm.Account
  248. storage merkle.Tree
  249. removed bool
  250. dirty bool
  251. }
  252. func (accInfo accountInfo) unpack() (*acm.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. }