journal.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. }
  117. )
  118. func (ch createObjectChange) revert(s *StateDB) {
  119. delete(s.stateObjects, *ch.account)
  120. delete(s.stateObjectsDirty, *ch.account)
  121. }
  122. func (ch createObjectChange) dirtied() *common.Address {
  123. return ch.account
  124. }
  125. func (ch resetObjectChange) revert(s *StateDB) {
  126. s.setStateObject(ch.prev)
  127. }
  128. func (ch resetObjectChange) dirtied() *common.Address {
  129. return nil
  130. }
  131. func (ch suicideChange) revert(s *StateDB) {
  132. obj := s.getStateObject(*ch.account)
  133. if obj != nil {
  134. obj.suicided = ch.prev
  135. obj.setBalance(ch.prevbalance)
  136. }
  137. }
  138. func (ch suicideChange) dirtied() *common.Address {
  139. return ch.account
  140. }
  141. var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
  142. func (ch touchChange) revert(s *StateDB) {
  143. }
  144. func (ch touchChange) dirtied() *common.Address {
  145. return ch.account
  146. }
  147. func (ch balanceChange) revert(s *StateDB) {
  148. s.getStateObject(*ch.account).setBalance(ch.prev)
  149. }
  150. func (ch balanceChange) dirtied() *common.Address {
  151. return ch.account
  152. }
  153. func (ch nonceChange) revert(s *StateDB) {
  154. s.getStateObject(*ch.account).setNonce(ch.prev)
  155. }
  156. func (ch nonceChange) dirtied() *common.Address {
  157. return ch.account
  158. }
  159. func (ch codeChange) revert(s *StateDB) {
  160. s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
  161. }
  162. func (ch codeChange) dirtied() *common.Address {
  163. return ch.account
  164. }
  165. func (ch storageChange) revert(s *StateDB) {
  166. s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
  167. }
  168. func (ch storageChange) dirtied() *common.Address {
  169. return ch.account
  170. }
  171. func (ch refundChange) revert(s *StateDB) {
  172. s.refund = ch.prev
  173. }
  174. func (ch refundChange) dirtied() *common.Address {
  175. return nil
  176. }
  177. func (ch addLogChange) revert(s *StateDB) {
  178. logs := s.logs[ch.txhash]
  179. if len(logs) == 1 {
  180. delete(s.logs, ch.txhash)
  181. } else {
  182. s.logs[ch.txhash] = logs[:len(logs)-1]
  183. }
  184. s.logSize--
  185. }
  186. func (ch addLogChange) dirtied() *common.Address {
  187. return nil
  188. }
  189. func (ch addPreimageChange) revert(s *StateDB) {
  190. delete(s.preimages, ch.hash)
  191. }
  192. func (ch addPreimageChange) dirtied() *common.Address {
  193. return nil
  194. }