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.

191 lines
4.6 KiB

  1. package state
  2. import (
  3. ac "github.com/tendermint/tendermint/account"
  4. . "github.com/tendermint/tendermint/common"
  5. "github.com/tendermint/tendermint/vm"
  6. "github.com/tendermint/tendermint/vm/sha3"
  7. )
  8. type TxCache struct {
  9. backend *BlockCache
  10. accounts map[Word256]vmAccountInfo
  11. storages map[Tuple256]Word256
  12. logs []*vm.Log
  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. logs: make([]*vm.Log, 0),
  20. }
  21. }
  22. //-------------------------------------
  23. // TxCache.account
  24. func (cache *TxCache) GetAccount(addr Word256) *vm.Account {
  25. acc, removed := vmUnpack(cache.accounts[addr])
  26. if removed {
  27. return nil
  28. } else {
  29. return acc
  30. }
  31. }
  32. func (cache *TxCache) UpdateAccount(acc *vm.Account) {
  33. addr := acc.Address
  34. // SANITY CHECK
  35. _, removed := vmUnpack(cache.accounts[addr])
  36. if removed {
  37. panic("UpdateAccount on a removed account")
  38. }
  39. // SANITY CHECK END
  40. cache.accounts[addr] = vmAccountInfo{acc, false}
  41. }
  42. func (cache *TxCache) RemoveAccount(acc *vm.Account) {
  43. addr := acc.Address
  44. // SANITY CHECK
  45. _, removed := vmUnpack(cache.accounts[addr])
  46. if removed {
  47. panic("RemoveAccount on a removed account")
  48. }
  49. // SANITY CHECK END
  50. cache.accounts[addr] = vmAccountInfo{acc, true}
  51. }
  52. // Creates a 20 byte address and bumps the creator's nonce.
  53. func (cache *TxCache) CreateAccount(creator *vm.Account) *vm.Account {
  54. // Generate an address
  55. nonce := creator.Nonce
  56. creator.Nonce += 1
  57. addr := RightPadWord256(NewContractAddress(creator.Address.Prefix(20), nonce))
  58. // Create account from address.
  59. account, removed := vmUnpack(cache.accounts[addr])
  60. if removed || account == nil {
  61. account = &vm.Account{
  62. Address: addr,
  63. Balance: 0,
  64. Code: nil,
  65. Nonce: 0,
  66. StorageRoot: Zero256,
  67. }
  68. cache.accounts[addr] = vmAccountInfo{account, false}
  69. return account
  70. } else {
  71. panic(Fmt("Could not create account, address already exists: %X", addr))
  72. }
  73. }
  74. // TxCache.account
  75. //-------------------------------------
  76. // TxCache.storage
  77. func (cache *TxCache) GetStorage(addr Word256, key Word256) Word256 {
  78. // Check cache
  79. value, ok := cache.storages[Tuple256{addr, key}]
  80. if ok {
  81. return value
  82. }
  83. // Load from backend
  84. return cache.backend.GetStorage(addr, key)
  85. }
  86. // NOTE: Set value to zero to removed from the trie.
  87. func (cache *TxCache) SetStorage(addr Word256, key Word256, value Word256) {
  88. _, removed := vmUnpack(cache.accounts[addr])
  89. if removed {
  90. panic("SetStorage() on a removed account")
  91. }
  92. cache.storages[Tuple256{addr, key}] = value
  93. }
  94. // TxCache.storage
  95. //-------------------------------------
  96. // These updates do not have to be in deterministic order,
  97. // the backend is responsible for ordering updates.
  98. func (cache *TxCache) Sync() {
  99. // Remove or update storage
  100. for addrKey, value := range cache.storages {
  101. addr, key := Tuple256Split(addrKey)
  102. cache.backend.SetStorage(addr, key, value)
  103. }
  104. // Remove or update accounts
  105. for addr, accInfo := range cache.accounts {
  106. acc, removed := vmUnpack(accInfo)
  107. if removed {
  108. cache.backend.RemoveAccount(addr.Prefix(20))
  109. } else {
  110. cache.backend.UpdateAccount(toStateAccount(acc))
  111. }
  112. }
  113. // TODO support logs, add them to the cache somehow.
  114. }
  115. func (cache *TxCache) AddLog(log *vm.Log) {
  116. cache.logs = append(cache.logs, log)
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Convenience function to return address of new contract
  120. func NewContractAddress(caller []byte, nonce uint64) []byte {
  121. temp := make([]byte, 32+8)
  122. copy(temp, caller)
  123. PutUint64(temp[32:], nonce)
  124. return sha3.Sha3(temp)[:20]
  125. }
  126. // Converts backend.Account to vm.Account struct.
  127. func toVMAccount(acc *ac.Account) *vm.Account {
  128. return &vm.Account{
  129. Address: RightPadWord256(acc.Address),
  130. Balance: acc.Balance,
  131. Code: acc.Code, // This is crazy.
  132. Nonce: uint64(acc.Sequence),
  133. StorageRoot: RightPadWord256(acc.StorageRoot),
  134. Other: acc.PubKey,
  135. }
  136. }
  137. // Converts vm.Account to backend.Account struct.
  138. func toStateAccount(acc *vm.Account) *ac.Account {
  139. pubKey, ok := acc.Other.(ac.PubKey)
  140. if !ok {
  141. pubKey = ac.PubKeyNil{}
  142. }
  143. var storageRoot []byte
  144. if acc.StorageRoot.IsZero() {
  145. storageRoot = nil
  146. } else {
  147. storageRoot = acc.StorageRoot.Bytes()
  148. }
  149. return &ac.Account{
  150. Address: acc.Address.Prefix(20),
  151. PubKey: pubKey,
  152. Balance: acc.Balance,
  153. Code: acc.Code,
  154. Sequence: uint(acc.Nonce),
  155. StorageRoot: storageRoot,
  156. }
  157. }
  158. type vmAccountInfo struct {
  159. account *vm.Account
  160. removed bool
  161. }
  162. func vmUnpack(accInfo vmAccountInfo) (*vm.Account, bool) {
  163. return accInfo.account, accInfo.removed
  164. }