github.com/datachainlab/burrow@v0.25.0/execution/evm/state.go (about) 1 package evm 2 3 import ( 4 "fmt" 5 6 "github.com/hyperledger/burrow/acm" 7 "github.com/hyperledger/burrow/acm/acmstate" 8 "github.com/hyperledger/burrow/binary" 9 "github.com/hyperledger/burrow/crypto" 10 "github.com/hyperledger/burrow/execution/errors" 11 "github.com/hyperledger/burrow/permission" 12 ) 13 14 type Interface interface { 15 Reader 16 Writer 17 // Capture any errors when accessing or writing state - will return nil if no errors have occurred so far 18 errors.Provider 19 errors.Sink 20 // Create a new cached state over this one inheriting any cache options 21 NewCache(cacheOptions ...acmstate.CacheOption) Interface 22 // Sync this state cache to into its originator 23 Sync() errors.CodedError 24 } 25 26 type Reader interface { 27 GetStorage(address crypto.Address, key binary.Word256) binary.Word256 28 GetBalance(address crypto.Address) uint64 29 GetPermissions(address crypto.Address) permission.AccountPermissions 30 GetCode(address crypto.Address) acm.Bytecode 31 GetSequence(address crypto.Address) uint64 32 Exists(address crypto.Address) bool 33 // GetBlockHash returns hash of the specific block 34 GetBlockHash(blockNumber uint64) (binary.Word256, error) 35 } 36 37 type Writer interface { 38 CreateAccount(address crypto.Address) 39 InitCode(address crypto.Address, code []byte) 40 RemoveAccount(address crypto.Address) 41 SetStorage(address crypto.Address, key, value binary.Word256) 42 AddToBalance(address crypto.Address, amount uint64) 43 SubtractFromBalance(address crypto.Address, amount uint64) 44 SetPermission(address crypto.Address, permFlag permission.PermFlag, value bool) 45 UnsetPermission(address crypto.Address, permFlag permission.PermFlag) 46 AddRole(address crypto.Address, role string) bool 47 RemoveRole(address crypto.Address, role string) bool 48 } 49 50 type State struct { 51 // Where we sync 52 backend acmstate.ReaderWriter 53 // Block chain info 54 blockHashGetter func(height uint64) []byte 55 // Cache this State wraps 56 cache *acmstate.Cache 57 // Any error that may have occurred 58 error errors.CodedError 59 // In order for nested cache to inherit any options 60 cacheOptions []acmstate.CacheOption 61 } 62 63 func NewState(st acmstate.ReaderWriter, blockHashGetter func(height uint64) []byte, cacheOptions ...acmstate.CacheOption) *State { 64 return &State{ 65 backend: st, 66 blockHashGetter: blockHashGetter, 67 cache: acmstate.NewCache(st, cacheOptions...), 68 cacheOptions: cacheOptions, 69 } 70 } 71 72 func (st *State) NewCache(cacheOptions ...acmstate.CacheOption) Interface { 73 return NewState(st.cache, st.blockHashGetter, append(st.cacheOptions, cacheOptions...)...) 74 } 75 76 func (st *State) Sync() errors.CodedError { 77 // Do not sync if we have erred 78 if st.error != nil { 79 return st.error 80 } 81 err := st.cache.Sync(st.backend) 82 if err != nil { 83 return errors.AsException(err) 84 } 85 return nil 86 } 87 88 func (st *State) Error() errors.CodedError { 89 if st.error == nil { 90 return nil 91 } 92 return st.error 93 } 94 95 // Errors pushed to state may end up in TxExecutions and therefore the merkle state so it is essential that errors are 96 // deterministic and independent of the code path taken to execution (e.g. replay takes a different path to that of 97 // normal consensus reactor so stack traces may differ - as they may across architectures) 98 func (st *State) PushError(err error) { 99 if st.error == nil { 100 // Make sure we are not wrapping a known nil value 101 ex := errors.AsException(err) 102 if ex != nil { 103 st.error = ex 104 } 105 } 106 } 107 108 // Reader 109 110 func (st *State) GetStorage(address crypto.Address, key binary.Word256) binary.Word256 { 111 value, err := st.cache.GetStorage(address, key) 112 if err != nil { 113 st.PushError(err) 114 return binary.Zero256 115 } 116 return value 117 } 118 119 func (st *State) GetBalance(address crypto.Address) uint64 { 120 acc := st.account(address) 121 if acc == nil { 122 return 0 123 } 124 return acc.Balance 125 } 126 127 func (st *State) GetPermissions(address crypto.Address) permission.AccountPermissions { 128 acc := st.account(address) 129 if acc == nil { 130 return permission.AccountPermissions{} 131 } 132 return acc.Permissions 133 } 134 135 func (st *State) GetCode(address crypto.Address) acm.Bytecode { 136 acc := st.account(address) 137 if acc == nil { 138 return nil 139 } 140 return acc.Code 141 } 142 143 func (st *State) Exists(address crypto.Address) bool { 144 acc, err := st.cache.GetAccount(address) 145 if err != nil { 146 st.PushError(err) 147 return false 148 } 149 if acc == nil { 150 return false 151 } 152 return true 153 } 154 155 func (st *State) GetSequence(address crypto.Address) uint64 { 156 acc := st.account(address) 157 if acc == nil { 158 return 0 159 } 160 return acc.Sequence 161 } 162 163 // Writer 164 165 func (st *State) CreateAccount(address crypto.Address) { 166 if st.Exists(address) { 167 st.PushError(errors.ErrorCodef(errors.ErrorCodeDuplicateAddress, 168 "tried to create an account at an address that already exists: %v", address)) 169 return 170 } 171 st.updateAccount(&acm.Account{Address: address}) 172 } 173 174 func (st *State) InitCode(address crypto.Address, code []byte) { 175 acc := st.mustAccount(address) 176 if acc == nil { 177 st.PushError(errors.ErrorCodef(errors.ErrorCodeInvalidAddress, 178 "tried to initialise code for an account that does not exist: %v", address)) 179 return 180 } 181 if acc.Code != nil { 182 st.PushError(errors.ErrorCodef(errors.ErrorCodeIllegalWrite, 183 "tried to initialise code for a contract that already exists: %v", address)) 184 return 185 } 186 acc.Code = code 187 st.updateAccount(acc) 188 } 189 190 func (st *State) RemoveAccount(address crypto.Address) { 191 if !st.Exists(address) { 192 st.PushError(errors.ErrorCodef(errors.ErrorCodeDuplicateAddress, 193 "tried to remove an account at an address that does not exist: %v", address)) 194 return 195 } 196 st.removeAccount(address) 197 } 198 199 func (st *State) SetStorage(address crypto.Address, key, value binary.Word256) { 200 err := st.cache.SetStorage(address, key, value) 201 if err != nil { 202 st.PushError(err) 203 } 204 } 205 206 func (st *State) AddToBalance(address crypto.Address, amount uint64) { 207 acc := st.mustAccount(address) 208 if acc == nil { 209 return 210 } 211 st.PushError(acc.AddToBalance(amount)) 212 st.updateAccount(acc) 213 } 214 215 func (st *State) SubtractFromBalance(address crypto.Address, amount uint64) { 216 acc := st.mustAccount(address) 217 if acc == nil { 218 return 219 } 220 st.PushError(acc.SubtractFromBalance(amount)) 221 st.updateAccount(acc) 222 } 223 224 func (st *State) SetPermission(address crypto.Address, permFlag permission.PermFlag, value bool) { 225 acc := st.mustAccount(address) 226 if acc == nil { 227 return 228 } 229 st.PushError(acc.Permissions.Base.Set(permFlag, value)) 230 st.updateAccount(acc) 231 } 232 233 func (st *State) UnsetPermission(address crypto.Address, permFlag permission.PermFlag) { 234 acc := st.mustAccount(address) 235 if acc == nil { 236 return 237 } 238 st.PushError(acc.Permissions.Base.Unset(permFlag)) 239 st.updateAccount(acc) 240 } 241 242 func (st *State) AddRole(address crypto.Address, role string) bool { 243 acc := st.mustAccount(address) 244 if acc == nil { 245 return false 246 } 247 added := acc.Permissions.AddRole(role) 248 st.updateAccount(acc) 249 return added 250 } 251 252 func (st *State) RemoveRole(address crypto.Address, role string) bool { 253 acc := st.mustAccount(address) 254 if acc == nil { 255 return false 256 } 257 removed := acc.Permissions.RemoveRole(role) 258 st.updateAccount(acc) 259 return removed 260 } 261 262 func (st *State) GetBlockHash(height uint64) (binary.Word256, error) { 263 hash := st.blockHashGetter(height) 264 if len(hash) == 0 { 265 st.PushError(fmt.Errorf("got empty BlockHash from blockHashGetter")) 266 } 267 return binary.LeftPadWord256(hash), nil 268 } 269 270 // Helpers 271 272 func (st *State) account(address crypto.Address) *acm.Account { 273 acc, err := st.cache.GetAccount(address) 274 if err != nil { 275 st.PushError(err) 276 } 277 return acc 278 } 279 280 func (st *State) mustAccount(address crypto.Address) *acm.Account { 281 acc := st.account(address) 282 if acc == nil { 283 st.PushError(errors.ErrorCodef(errors.ErrorCodeIllegalWrite, 284 "attempted to modify non-existent account: %v", address)) 285 } 286 return acc 287 } 288 289 func (st *State) updateAccount(account *acm.Account) { 290 err := st.cache.UpdateAccount(account) 291 if err != nil { 292 st.PushError(err) 293 } 294 } 295 296 func (st *State) removeAccount(address crypto.Address) { 297 err := st.cache.RemoveAccount(address) 298 if err != nil { 299 st.PushError(err) 300 } 301 }