journal.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package state
  17. import (
  18. "math/big"
  19. "github.com/ethereum/go-ethereum/common"
  20. )
  21. // journalEntry is a modification entry in the state change journal that can be
  22. // reverted on demand.
  23. type journalEntry interface {
  24. // revert undoes the changes introduced by this journal entry.
  25. revert(*StateDB)
  26. // dirtied returns the Ethereum address modified by this journal entry.
  27. dirtied() *common.Address
  28. }
  29. // journal contains the list of state modifications applied since the last state
  30. // commit. These are tracked to be able to be reverted in case of an execution
  31. // exception or revertal request.
  32. type journal struct {
  33. entries []journalEntry // Current changes tracked by the journal
  34. dirties map[common.Address]int // Dirty accounts and the number of changes
  35. }
  36. // newJournal create a new initialized journal.
  37. func newJournal() *journal {
  38. return &journal{
  39. dirties: make(map[common.Address]int),
  40. }
  41. }
  42. // append inserts a new modification entry to the end of the change journal.
  43. func (j *journal) append(entry journalEntry) {
  44. j.entries = append(j.entries, entry)
  45. if addr := entry.dirtied(); addr != nil {
  46. j.dirties[*addr]++
  47. }
  48. }
  49. // revert undoes a batch of journalled modifications along with any reverted
  50. // dirty handling too.
  51. func (j *journal) revert(statedb *StateDB, snapshot int) {
  52. for i := len(j.entries) - 1; i >= snapshot; i-- {
  53. // Undo the changes made by the operation
  54. j.entries[i].revert(statedb)
  55. // Drop any dirty tracking induced by the change
  56. if addr := j.entries[i].dirtied(); addr != nil {
  57. if j.dirties[*addr]--; j.dirties[*addr] == 0 {
  58. delete(j.dirties, *addr)
  59. }
  60. }
  61. }
  62. j.entries = j.entries[:snapshot]
  63. }
  64. // dirty explicitly sets an address to dirty, even if the change entries would
  65. // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
  66. // precompile consensus exception.
  67. func (j *journal) dirty(addr common.Address) {
  68. j.dirties[addr]++
  69. }
  70. // length returns the current number of entries in the journal.
  71. func (j *journal) length() int {
  72. return len(j.entries)
  73. }
  74. type (
  75. // Changes to the account trie.
  76. createObjectChange struct {
  77. account *common.Address
  78. }
  79. resetObjectChange struct {
  80. prev *stateObject
  81. }
  82. suicideChange struct {
  83. account *common.Address
  84. prev bool // whether account had already suicided
  85. prevbalance *big.Int
  86. }
  87. // Changes to individual accounts.
  88. balanceChange struct {
  89. account *common.Address
  90. prev *big.Int
  91. }
  92. nonceChange struct {
  93. account *common.Address
  94. prev uint64
  95. }
  96. storageChange struct {
  97. account *common.Address
  98. key, prevalue common.Hash
  99. }
  100. codeChange struct {
  101. account *common.Address
  102. prevcode, prevhash []byte
  103. }
  104. // Changes to other state values.
  105. refundChange struct {
  106. prev uint64
  107. }
  108. addLogChange struct {
  109. txhash common.Hash
  110. }
  111. addPreimageChange struct {
  112. hash common.Hash
  113. }
  114. touchChange struct {
  115. account *common.Address
  116. prev bool
  117. prevDirty bool
  118. }
  119. )
  120. func (ch createObjectChange) revert(s *StateDB) {
  121. delete(s.stateObjects, *ch.account)
  122. delete(s.stateObjectsDirty, *ch.account)
  123. }
  124. func (ch createObjectChange) dirtied() *common.Address {
  125. return ch.account
  126. }
  127. func (ch resetObjectChange) revert(s *StateDB) {
  128. s.setStateObject(ch.prev)
  129. }
  130. func (ch resetObjectChange) dirtied() *common.Address {
  131. return nil
  132. }
  133. func (ch suicideChange) revert(s *StateDB) {
  134. obj := s.getStateObject(*ch.account)
  135. if obj != nil {
  136. obj.suicided = ch.prev
  137. obj.setBalance(ch.prevbalance)
  138. }
  139. }
  140. func (ch suicideChange) dirtied() *common.Address {
  141. return ch.account
  142. }
  143. var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
  144. func (ch touchChange) revert(s *StateDB) {
  145. }
  146. func (ch touchChange) dirtied() *common.Address {
  147. return ch.account
  148. }
  149. func (ch balanceChange) revert(s *StateDB) {
  150. s.getStateObject(*ch.account).setBalance(ch.prev)
  151. }
  152. func (ch balanceChange) dirtied() *common.Address {
  153. return ch.account
  154. }
  155. func (ch nonceChange) revert(s *StateDB) {
  156. s.getStateObject(*ch.account).setNonce(ch.prev)
  157. }
  158. func (ch nonceChange) dirtied() *common.Address {
  159. return ch.account
  160. }
  161. func (ch codeChange) revert(s *StateDB) {
  162. s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
  163. }
  164. func (ch codeChange) dirtied() *common.Address {
  165. return ch.account
  166. }
  167. func (ch storageChange) revert(s *StateDB) {
  168. s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
  169. }
  170. func (ch storageChange) dirtied() *common.Address {
  171. return ch.account
  172. }
  173. func (ch refundChange) revert(s *StateDB) {
  174. s.refund = ch.prev
  175. }
  176. func (ch refundChange) dirtied() *common.Address {
  177. return nil
  178. }
  179. func (ch addLogChange) revert(s *StateDB) {
  180. logs := s.logs[ch.txhash]
  181. if len(logs) == 1 {
  182. delete(s.logs, ch.txhash)
  183. } else {
  184. s.logs[ch.txhash] = logs[:len(logs)-1]
  185. }
  186. s.logSize--
  187. }
  188. func (ch addLogChange) dirtied() *common.Address {
  189. return nil
  190. }
  191. func (ch addPreimageChange) revert(s *StateDB) {
  192. delete(s.preimages, ch.hash)
  193. }
  194. func (ch addPreimageChange) dirtied() *common.Address {
  195. return nil
  196. }