github.com/igggame/nebulas-go@v2.1.0+incompatible/core/state/account_state.go (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package state 20 21 import ( 22 "errors" 23 "fmt" 24 25 "github.com/gogo/protobuf/proto" 26 "github.com/nebulasio/go-nebulas/common/trie" 27 "github.com/nebulasio/go-nebulas/core/pb" 28 "github.com/nebulasio/go-nebulas/storage" 29 "github.com/nebulasio/go-nebulas/util" 30 "github.com/nebulasio/go-nebulas/util/byteutils" 31 ) 32 33 // Errors 34 var ( 35 ErrBalanceInsufficient = errors.New("cannot subtract a value which is bigger than current balance") 36 ErrAccountNotFound = errors.New("cannot found account in storage") 37 ErrContractAccountNotFound = errors.New("cannot found contract account in storage please check contract address is valid or deploy is success") 38 ) 39 40 // account info in state Trie 41 type account struct { 42 address byteutils.Hash 43 balance *util.Uint128 44 nonce uint64 45 // UserType: Global Storage 46 // ContractType: Local Storage 47 variables *trie.Trie 48 // ContractType: Transaction Hash 49 birthPlace byteutils.Hash 50 51 contractMeta *corepb.ContractMeta 52 } 53 54 // ToBytes converts domain Account to bytes 55 func (acc *account) ToBytes() ([]byte, error) { 56 value, err := acc.balance.ToFixedSizeByteSlice() 57 if err != nil { 58 return nil, err 59 } 60 pbAcc := &corepb.Account{ 61 Address: acc.address, 62 Balance: value, 63 Nonce: acc.nonce, 64 VarsHash: acc.variables.RootHash(), 65 BirthPlace: acc.birthPlace, 66 ContractMeta: acc.contractMeta, 67 } 68 bytes, err := proto.Marshal(pbAcc) 69 if err != nil { 70 return nil, err 71 } 72 return bytes, nil 73 } 74 75 // FromBytes converts bytes to Account 76 func (acc *account) FromBytes(bytes []byte, storage storage.Storage) error { 77 pbAcc := &corepb.Account{} 78 if err := proto.Unmarshal(bytes, pbAcc); err != nil { 79 return err 80 } 81 value, err := util.NewUint128FromFixedSizeByteSlice(pbAcc.Balance) 82 if err != nil { 83 return err 84 } 85 acc.address = pbAcc.Address 86 acc.balance = value 87 acc.nonce = pbAcc.Nonce 88 acc.birthPlace = pbAcc.BirthPlace 89 acc.contractMeta = pbAcc.ContractMeta 90 acc.variables, err = trie.NewTrie(pbAcc.VarsHash, storage, false) 91 if err != nil { 92 return err 93 } 94 return nil 95 } 96 97 // Balance return account's balance 98 func (acc *account) Balance() *util.Uint128 { 99 return acc.balance 100 } 101 102 // Address return account's address 103 func (acc *account) Address() byteutils.Hash { 104 return acc.address 105 } 106 107 // Nonce return account's nonce 108 func (acc *account) Nonce() uint64 { 109 return acc.nonce 110 } 111 112 // VarsHash return account's variables hash 113 func (acc *account) VarsHash() byteutils.Hash { 114 return acc.variables.RootHash() 115 } 116 117 // BirthPlace return account's birth place 118 func (acc *account) BirthPlace() byteutils.Hash { 119 return acc.birthPlace 120 } 121 122 // ContractMeta .. 123 func (acc *account) ContractMeta() *corepb.ContractMeta { 124 return acc.contractMeta 125 } 126 127 // Clone account 128 func (acc *account) Clone() (Account, error) { 129 variables, err := acc.variables.Clone() 130 if err != nil { 131 return nil, err 132 } 133 134 return &account{ 135 address: acc.address, 136 balance: acc.balance, 137 nonce: acc.nonce, 138 variables: variables, 139 birthPlace: acc.birthPlace, 140 contractMeta: acc.contractMeta, // TODO: Clone() ? 141 }, nil 142 } 143 144 // IncrNonce by 1 145 func (acc *account) IncrNonce() { 146 acc.nonce++ 147 } 148 149 // AddBalance to an account 150 func (acc *account) AddBalance(value *util.Uint128) error { 151 balance, err := acc.balance.Add(value) 152 if err != nil { 153 return err 154 } 155 acc.balance = balance 156 return nil 157 } 158 159 // SubBalance to an account 160 func (acc *account) SubBalance(value *util.Uint128) error { 161 if acc.balance.Cmp(value) < 0 { 162 return ErrBalanceInsufficient 163 } 164 balance, err := acc.balance.Sub(value) 165 if err != nil { 166 return err 167 } 168 acc.balance = balance 169 return nil 170 } 171 172 // Put into account's storage 173 func (acc *account) Put(key []byte, value []byte) error { 174 _, err := acc.variables.Put(key, value) 175 return err 176 } 177 178 // Get from account's storage 179 func (acc *account) Get(key []byte) ([]byte, error) { 180 return acc.variables.Get(key) 181 } 182 183 // Del from account's storage 184 func (acc *account) Del(key []byte) error { 185 if _, err := acc.variables.Del(key); err != nil { 186 return err 187 } 188 return nil 189 } 190 191 // Iterator map var from account's storage 192 func (acc *account) Iterator(prefix []byte) (Iterator, error) { 193 return acc.variables.Iterator(prefix) 194 } 195 196 func (acc *account) String() string { 197 return fmt.Sprintf("Account %p {Address: %v, Balance:%v; Nonce:%v; VarsHash:%v; BirthPlace:%v; ContractMeta:%v}", 198 acc, 199 byteutils.Hex(acc.address), 200 acc.balance, 201 acc.nonce, 202 byteutils.Hex(acc.variables.RootHash()), 203 acc.birthPlace.Hex(), 204 acc.contractMeta.String(), // TODO: check nil? 205 ) 206 } 207 208 // AccountState manage account state in Block 209 type accountState struct { 210 stateTrie *trie.Trie 211 dirtyAccount map[byteutils.HexHash]Account 212 storage storage.Storage 213 } 214 215 // NewAccountState create a new account state 216 func NewAccountState(root byteutils.Hash, storage storage.Storage) (AccountState, error) { 217 stateTrie, err := trie.NewTrie(root, storage, false) 218 if err != nil { 219 return nil, err 220 } 221 222 return &accountState{ 223 stateTrie: stateTrie, 224 dirtyAccount: make(map[byteutils.HexHash]Account), 225 storage: storage, 226 }, nil 227 } 228 229 func (as *accountState) recordDirtyAccount(addr byteutils.Hash, acc Account) { 230 as.dirtyAccount[addr.Hex()] = acc 231 } 232 233 func (as *accountState) newAccount(addr byteutils.Hash, birthPlace byteutils.Hash, contractMeta *corepb.ContractMeta) (Account, error) { 234 varTrie, err := trie.NewTrie(nil, as.storage, false) 235 if err != nil { 236 return nil, err 237 } 238 acc := &account{ 239 address: addr, 240 balance: util.NewUint128(), 241 nonce: 0, 242 variables: varTrie, 243 birthPlace: birthPlace, 244 contractMeta: contractMeta, 245 } 246 as.recordDirtyAccount(addr, acc) 247 return acc, nil 248 } 249 250 func (as *accountState) getAccount(addr byteutils.Hash) (Account, error) { 251 // search in dirty account 252 if acc, ok := as.dirtyAccount[addr.Hex()]; ok { 253 return acc, nil 254 } 255 // search in storage 256 bytes, err := as.stateTrie.Get(addr) 257 if err != nil && err != storage.ErrKeyNotFound { 258 return nil, err 259 } 260 if err == nil { 261 acc := new(account) 262 err = acc.FromBytes(bytes, as.storage) 263 if err != nil { 264 return nil, err 265 } 266 as.recordDirtyAccount(addr, acc) 267 return acc, nil 268 } 269 return nil, ErrAccountNotFound 270 } 271 272 func (as *accountState) Flush() error { 273 for addr, acc := range as.dirtyAccount { 274 bytes, err := acc.ToBytes() 275 if err != nil { 276 return err 277 } 278 key, err := addr.Hash() 279 if err != nil { 280 return err 281 } 282 as.stateTrie.Put(key, bytes) 283 } 284 as.dirtyAccount = make(map[byteutils.HexHash]Account) 285 return nil 286 } 287 288 func (as *accountState) Abort() error { 289 as.dirtyAccount = make(map[byteutils.HexHash]Account) 290 return nil 291 } 292 293 // RootHash return root hash of account state 294 func (as *accountState) RootHash() byteutils.Hash { 295 return as.stateTrie.RootHash() 296 } 297 298 // GetOrCreateUserAccount according to the addr 299 func (as *accountState) GetOrCreateUserAccount(addr byteutils.Hash) (Account, error) { 300 acc, err := as.getAccount(addr) 301 if err != nil && err != ErrAccountNotFound { 302 return nil, err 303 } 304 if err == ErrAccountNotFound { 305 acc, err = as.newAccount(addr, nil, nil) 306 if err != nil { 307 return nil, err 308 } 309 return acc, nil 310 } 311 return acc, nil 312 } 313 314 // GetContractAccount from current AccountState 315 func (as *accountState) GetContractAccount(addr byteutils.Hash) (Account, error) { 316 acc, err := as.getAccount(addr) 317 318 if err == ErrAccountNotFound { 319 err = ErrContractAccountNotFound 320 } 321 if err != nil { 322 return nil, err 323 } 324 325 return acc, nil 326 } 327 328 // CreateContractAccount according to the addr, and set birthPlace as creation tx hash 329 func (as *accountState) CreateContractAccount(addr byteutils.Hash, birthPlace byteutils.Hash, contractMeta *corepb.ContractMeta) (Account, error) { 330 return as.newAccount(addr, birthPlace, contractMeta) 331 } 332 333 func (as *accountState) Accounts() ([]Account, error) { // TODO delete 334 accounts := []Account{} 335 iter, err := as.stateTrie.Iterator(nil) 336 if err != nil && err != storage.ErrKeyNotFound { 337 return nil, err 338 } 339 if err != nil { 340 return accounts, nil 341 } 342 exist, err := iter.Next() 343 if err != nil { 344 return nil, err 345 } 346 for exist { 347 acc := new(account) 348 err = acc.FromBytes(iter.Value(), as.storage) 349 if err != nil { 350 return nil, err 351 } 352 accounts = append(accounts, acc) 353 exist, err = iter.Next() 354 if err != nil { 355 return nil, err 356 } 357 } 358 return accounts, nil 359 } 360 361 // DirtyAccounts return all changed accounts 362 func (as *accountState) DirtyAccounts() ([]Account, error) { 363 accounts := []Account{} 364 for _, account := range as.dirtyAccount { 365 accounts = append(accounts, account) 366 } 367 return accounts, nil 368 } 369 370 // Relay merge the done account state 371 func (as *accountState) Replay(done AccountState) error { 372 state := done.(*accountState) 373 for addr, acc := range state.dirtyAccount { 374 as.dirtyAccount[addr] = acc 375 } 376 return nil 377 } 378 379 // Clone an accountState 380 func (as *accountState) Clone() (AccountState, error) { 381 stateTrie, err := as.stateTrie.Clone() 382 if err != nil { 383 return nil, err 384 } 385 386 dirtyAccount := make(map[byteutils.HexHash]Account) 387 for addr, acc := range as.dirtyAccount { 388 dirtyAccount[addr], err = acc.Clone() 389 if err != nil { 390 return nil, err 391 } 392 } 393 394 return &accountState{ 395 stateTrie: stateTrie, 396 dirtyAccount: dirtyAccount, 397 storage: as.storage, 398 }, nil 399 } 400 401 func (as *accountState) String() string { 402 return fmt.Sprintf("AccountState %p {RootHash:%s; dirtyAccount:%v; Storage:%p}", 403 as, 404 byteutils.Hex(as.stateTrie.RootHash()), 405 as.dirtyAccount, 406 as.storage, 407 ) 408 } 409 410 // MockAccount nf/nvm/engine.CheckV8Run() & cmd/v8/main.go 411 func MockAccount(version string) Account { 412 return &account{ 413 contractMeta: &corepb.ContractMeta{ 414 Version: version, 415 }, 416 } 417 }