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.

198 lines
5.0 KiB

  1. package state
  2. import (
  3. acm "github.com/tendermint/tendermint/account"
  4. . "github.com/tendermint/tendermint/common"
  5. ptypes "github.com/tendermint/tendermint/permission/types" // for GlobalPermissionAddress ...
  6. "github.com/tendermint/tendermint/types"
  7. "github.com/tendermint/tendermint/vm"
  8. )
  9. type TxCache struct {
  10. backend *BlockCache
  11. accounts map[Word256]vmAccountInfo
  12. storages map[Tuple256]Word256
  13. }
  14. func NewTxCache(backend *BlockCache) *TxCache {
  15. return &TxCache{
  16. backend: backend,
  17. accounts: make(map[Word256]vmAccountInfo),
  18. storages: make(map[Tuple256]Word256),
  19. }
  20. }
  21. //-------------------------------------
  22. // TxCache.account
  23. func (cache *TxCache) GetAccount(addr Word256) *vm.Account {
  24. acc, removed := cache.accounts[addr].unpack()
  25. if removed {
  26. return nil
  27. } else if acc == nil {
  28. acc2 := cache.backend.GetAccount(addr.Postfix(20))
  29. if acc2 != nil {
  30. return toVMAccount(acc2)
  31. }
  32. }
  33. return acc
  34. }
  35. func (cache *TxCache) UpdateAccount(acc *vm.Account) {
  36. addr := acc.Address
  37. _, removed := cache.accounts[addr].unpack()
  38. if removed {
  39. PanicSanity("UpdateAccount on a removed account")
  40. }
  41. cache.accounts[addr] = vmAccountInfo{acc, false}
  42. }
  43. func (cache *TxCache) RemoveAccount(acc *vm.Account) {
  44. addr := acc.Address
  45. _, removed := cache.accounts[addr].unpack()
  46. if removed {
  47. PanicSanity("RemoveAccount on a removed account")
  48. }
  49. cache.accounts[addr] = vmAccountInfo{acc, true}
  50. }
  51. // Creates a 20 byte address and bumps the creator's nonce.
  52. func (cache *TxCache) CreateAccount(creator *vm.Account) *vm.Account {
  53. // Generate an address
  54. nonce := creator.Nonce
  55. creator.Nonce += 1
  56. addr := LeftPadWord256(NewContractAddress(creator.Address.Postfix(20), int(nonce)))
  57. // Create account from address.
  58. account, removed := cache.accounts[addr].unpack()
  59. if removed || account == nil {
  60. account = &vm.Account{
  61. Address: addr,
  62. Balance: 0,
  63. Code: nil,
  64. Nonce: 0,
  65. Permissions: cache.GetAccount(ptypes.GlobalPermissionsAddress256).Permissions,
  66. Other: vmAccountOther{
  67. PubKey: nil,
  68. StorageRoot: nil,
  69. },
  70. }
  71. cache.accounts[addr] = vmAccountInfo{account, false}
  72. return account
  73. } else {
  74. // either we've messed up nonce handling, or sha3 is broken
  75. PanicSanity(Fmt("Could not create account, address already exists: %X", addr))
  76. return nil
  77. }
  78. }
  79. // TxCache.account
  80. //-------------------------------------
  81. // TxCache.storage
  82. func (cache *TxCache) GetStorage(addr Word256, key Word256) Word256 {
  83. // Check cache
  84. value, ok := cache.storages[Tuple256{addr, key}]
  85. if ok {
  86. return value
  87. }
  88. // Load from backend
  89. return cache.backend.GetStorage(addr, key)
  90. }
  91. // NOTE: Set value to zero to removed from the trie.
  92. func (cache *TxCache) SetStorage(addr Word256, key Word256, value Word256) {
  93. _, removed := cache.accounts[addr].unpack()
  94. if removed {
  95. PanicSanity("SetStorage() on a removed account")
  96. }
  97. cache.storages[Tuple256{addr, key}] = value
  98. }
  99. // TxCache.storage
  100. //-------------------------------------
  101. // These updates do not have to be in deterministic order,
  102. // the backend is responsible for ordering updates.
  103. func (cache *TxCache) Sync() {
  104. // Remove or update storage
  105. for addrKey, value := range cache.storages {
  106. addr, key := Tuple256Split(addrKey)
  107. cache.backend.SetStorage(addr, key, value)
  108. }
  109. // Remove or update accounts
  110. for addr, accInfo := range cache.accounts {
  111. acc, removed := accInfo.unpack()
  112. if removed {
  113. cache.backend.RemoveAccount(addr.Postfix(20))
  114. } else {
  115. cache.backend.UpdateAccount(toStateAccount(acc))
  116. }
  117. }
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Convenience function to return address of new contract
  121. func NewContractAddress(caller []byte, nonce int) []byte {
  122. return types.NewContractAddress(caller, nonce)
  123. }
  124. // Converts backend.Account to vm.Account struct.
  125. func toVMAccount(acc *acm.Account) *vm.Account {
  126. return &vm.Account{
  127. Address: LeftPadWord256(acc.Address),
  128. Balance: acc.Balance,
  129. Code: acc.Code, // This is crazy.
  130. Nonce: int64(acc.Sequence),
  131. Permissions: acc.Permissions, // Copy
  132. Other: vmAccountOther{
  133. PubKey: acc.PubKey,
  134. StorageRoot: acc.StorageRoot,
  135. },
  136. }
  137. }
  138. // Converts vm.Account to backend.Account struct.
  139. func toStateAccount(acc *vm.Account) *acm.Account {
  140. var pubKey acm.PubKey
  141. var storageRoot []byte
  142. if acc.Other != nil {
  143. pubKey, storageRoot = acc.Other.(vmAccountOther).unpack()
  144. }
  145. return &acm.Account{
  146. Address: acc.Address.Postfix(20),
  147. PubKey: pubKey,
  148. Balance: acc.Balance,
  149. Code: acc.Code,
  150. Sequence: int(acc.Nonce),
  151. StorageRoot: storageRoot,
  152. Permissions: acc.Permissions, // Copy
  153. }
  154. }
  155. // Everything in acmAccount that doesn't belong in
  156. // exported vmAccount fields.
  157. type vmAccountOther struct {
  158. PubKey acm.PubKey
  159. StorageRoot []byte
  160. }
  161. func (accOther vmAccountOther) unpack() (acm.PubKey, []byte) {
  162. return accOther.PubKey, accOther.StorageRoot
  163. }
  164. type vmAccountInfo struct {
  165. account *vm.Account
  166. removed bool
  167. }
  168. func (accInfo vmAccountInfo) unpack() (*vm.Account, bool) {
  169. return accInfo.account, accInfo.removed
  170. }