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.

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