github.com/annchain/OG@v0.0.9/arefactor_core/core/state/preload_db.go (about)

     1  package state
     2  
     3  import (
     4  	ogTypes "github.com/annchain/OG/arefactor/og_interface"
     5  	crypto "github.com/annchain/OG/arefactor/ogcrypto"
     6  	"github.com/annchain/OG/common/math"
     7  	"github.com/annchain/OG/types/token"
     8  	vmtypes "github.com/annchain/OG/vm/types"
     9  	log "github.com/sirupsen/logrus"
    10  )
    11  
    12  type PreloadDB struct {
    13  	root ogTypes.Hash
    14  
    15  	db Database
    16  	sd *StateDB
    17  
    18  	trie      Trie
    19  	worldTrie Trie
    20  
    21  	// journal records every action which will change statedb's data
    22  	// and it's for VM term revert only.
    23  	journal *journal
    24  
    25  	// states stores all the active state object, any changes on stateobject
    26  	// will also update states.
    27  	states   map[ogTypes.AddressKey]*StateObject
    28  	dirtyset map[ogTypes.AddressKey]struct{}
    29  }
    30  
    31  func NewPreloadDB(db Database, statedb *StateDB) *PreloadDB {
    32  	return &PreloadDB{
    33  		root:     statedb.Root(),
    34  		db:       db,
    35  		sd:       statedb,
    36  		journal:  newJournal(),
    37  		states:   make(map[ogTypes.AddressKey]*StateObject),
    38  		dirtyset: make(map[ogTypes.AddressKey]struct{}),
    39  	}
    40  }
    41  
    42  func (pd *PreloadDB) Reset() {
    43  	pd.trie = nil
    44  	pd.journal = newJournal()
    45  	pd.states = make(map[ogTypes.AddressKey]*StateObject)
    46  	pd.dirtyset = make(map[ogTypes.AddressKey]struct{})
    47  }
    48  
    49  func (pd *PreloadDB) getOrCreateStateObject(addr ogTypes.Address) *StateObject {
    50  	state := pd.getStateObject(addr)
    51  	if state == nil {
    52  		pd.CreateAccount(addr)
    53  		state = pd.getStateObject(addr)
    54  	}
    55  	return state
    56  }
    57  
    58  func (pd *PreloadDB) getStateObject(addr ogTypes.Address) *StateObject {
    59  	state, exist := pd.states[addr.AddressKey()]
    60  	if !exist {
    61  		sdState := pd.sd.GetStateObject(addr)
    62  		if sdState == nil {
    63  			return nil
    64  		}
    65  		state = NewStateObject(addr, pd)
    66  		state.Copy(sdState)
    67  		pd.states[addr.AddressKey()] = state
    68  	}
    69  	return state
    70  }
    71  
    72  func (pd *PreloadDB) CreateAccount(addr ogTypes.Address) {
    73  	newstate := NewStateObject(addr, pd)
    74  	oldstate := pd.sd.GetStateObject(addr)
    75  	if oldstate != nil {
    76  		pd.AppendJournal(&resetObjectChange{
    77  			account: oldstate.address,
    78  			prev:    oldstate,
    79  		})
    80  	} else {
    81  		pd.AppendJournal(&createObjectChange{
    82  			account: addr,
    83  		})
    84  	}
    85  	pd.states[addr.AddressKey()] = newstate
    86  
    87  }
    88  
    89  func (pd *PreloadDB) SubBalance(addr ogTypes.Address, decrement *math.BigInt) {
    90  	pd.subBalance(addr, token.OGTokenID, decrement)
    91  }
    92  func (pd *PreloadDB) SubTokenBalance(addr ogTypes.Address, tokenID int32, decrement *math.BigInt) {
    93  	pd.subBalance(addr, tokenID, decrement)
    94  }
    95  func (pd *PreloadDB) subBalance(addr ogTypes.Address, tokenID int32, decrement *math.BigInt) {
    96  	// check if increment is zero
    97  	if decrement.Sign() == 0 {
    98  		return
    99  	}
   100  	state := pd.getOrCreateStateObject(addr)
   101  	pd.setBalance(addr, tokenID, state.data.Balances.PreSub(tokenID, decrement))
   102  }
   103  
   104  func (pd *PreloadDB) AddBalance(addr ogTypes.Address, increment *math.BigInt) {
   105  	pd.addBalance(addr, token.OGTokenID, increment)
   106  }
   107  func (pd *PreloadDB) AddTokenBalance(addr ogTypes.Address, tokenID int32, increment *math.BigInt) {
   108  	pd.addBalance(addr, tokenID, increment)
   109  }
   110  func (pd *PreloadDB) addBalance(addr ogTypes.Address, tokenID int32, increment *math.BigInt) {
   111  	// check if increment is zero
   112  	if increment.Sign() == 0 {
   113  		return
   114  	}
   115  	state := pd.getOrCreateStateObject(addr)
   116  	pd.setBalance(addr, tokenID, state.data.Balances.PreAdd(tokenID, increment))
   117  }
   118  
   119  func (ps *PreloadDB) SetTokenBalance(addr ogTypes.Address, tokenID int32, balance *math.BigInt) {
   120  	ps.setBalance(addr, tokenID, balance)
   121  }
   122  func (pd *PreloadDB) setBalance(addr ogTypes.Address, tokenID int32, balance *math.BigInt) {
   123  	state := pd.getOrCreateStateObject(addr)
   124  	state.SetBalance(tokenID, balance)
   125  }
   126  
   127  // Retrieve the balance from the given address or 0 if object not found
   128  func (pd *PreloadDB) GetBalance(addr ogTypes.Address) *math.BigInt {
   129  	return pd.getBalance(addr, token.OGTokenID)
   130  }
   131  func (pd *PreloadDB) GetTokenBalance(addr ogTypes.Address, tokenID int32) *math.BigInt {
   132  	return pd.getBalance(addr, tokenID)
   133  }
   134  func (pd *PreloadDB) getBalance(addr ogTypes.Address, tokenID int32) *math.BigInt {
   135  	state := pd.getStateObject(addr)
   136  	if state == nil {
   137  		return math.NewBigInt(0)
   138  	}
   139  	return state.GetBalance(tokenID)
   140  }
   141  
   142  func (pd *PreloadDB) GetNonce(addr ogTypes.Address) uint64 {
   143  	state := pd.getStateObject(addr)
   144  	if state == nil {
   145  		return 0
   146  	}
   147  	return state.GetNonce()
   148  }
   149  func (pd *PreloadDB) SetNonce(addr ogTypes.Address, nonce uint64) {
   150  	state := pd.getOrCreateStateObject(addr)
   151  	state.SetNonce(nonce)
   152  }
   153  
   154  func (pd *PreloadDB) GetCodeHash(addr ogTypes.Address) ogTypes.Hash {
   155  	state := pd.getStateObject(addr)
   156  	if state == nil {
   157  		return nil
   158  	}
   159  	return state.GetCodeHash()
   160  }
   161  
   162  func (pd *PreloadDB) GetCode(addr ogTypes.Address) []byte {
   163  	state := pd.getStateObject(addr)
   164  	if state == nil {
   165  		return nil
   166  	}
   167  	return state.GetCode(pd.db)
   168  }
   169  
   170  func (pd *PreloadDB) SetCode(addr ogTypes.Address, code []byte) {
   171  	state := pd.getOrCreateStateObject(addr)
   172  	state.SetCode(ogTypes.BytesToHash32(crypto.Keccak256Hash(code)), code)
   173  }
   174  
   175  func (pd *PreloadDB) GetCodeSize(addr ogTypes.Address) int {
   176  	state := pd.getStateObject(addr)
   177  	if state == nil {
   178  		return 0
   179  	}
   180  	l, dberr := state.GetCodeSize(pd.db)
   181  	if dberr != nil {
   182  		log.Errorf("get code size from obj error: %v, obj: %s", dberr, state.address.AddressShortString())
   183  		return 0
   184  	}
   185  	return l
   186  }
   187  
   188  func (pd *PreloadDB) AddRefund(uint64)  {}
   189  func (pd *PreloadDB) SubRefund(uint64)  {}
   190  func (pd *PreloadDB) GetRefund() uint64 { return 0 }
   191  
   192  func (pd *PreloadDB) GetCommittedState(addr ogTypes.Address, key ogTypes.Hash) ogTypes.Hash {
   193  	state := pd.getStateObject(addr)
   194  	if state == nil {
   195  		return &emptyStateHash
   196  	}
   197  	return state.GetCommittedState(pd.db, key)
   198  }
   199  
   200  // GetState retrieves a value from the given account's storage trie.
   201  func (pd *PreloadDB) GetState(addr ogTypes.Address, key ogTypes.Hash) ogTypes.Hash {
   202  	state := pd.getStateObject(addr)
   203  	if state == nil {
   204  		return &emptyStateHash
   205  	}
   206  	return state.GetState(pd.db, key)
   207  }
   208  
   209  func (pd *PreloadDB) SetState(addr ogTypes.Address, key, value ogTypes.Hash) {
   210  	state := pd.getOrCreateStateObject(addr)
   211  	if state == nil {
   212  		return
   213  	}
   214  	state.SetState(pd.db, key, value)
   215  }
   216  
   217  func (pd *PreloadDB) Commit() (ogTypes.Hash, error) {
   218  	trie, err := pd.db.OpenTrie(pd.sd.Root())
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	pd.trie = trie
   223  
   224  	// update dirtyset according to journal
   225  	for addr := range pd.journal.dirties {
   226  		pd.dirtyset[addr.AddressKey()] = struct{}{}
   227  	}
   228  	for addr, state := range pd.states {
   229  		if _, isdirty := pd.dirtyset[addr]; !isdirty {
   230  			continue
   231  		}
   232  		log.Tracef("commit preload state, addr: %s, state: %s", addr, state.String())
   233  		// commit state's code
   234  		if state.code != nil && state.dirtycode {
   235  			pd.db.TrieDB().Insert(state.GetCodeHash(), state.code)
   236  			state.dirtycode = false
   237  		}
   238  		// commit state's storage
   239  		if err := state.CommitStorage(pd.db, true); err != nil {
   240  			log.Errorf("commit state's storage error: %v", err)
   241  		}
   242  		// update state data in current trie.
   243  		data, _ := state.Encode()
   244  		if err := pd.trie.TryUpdate(addr.Bytes(), data); err != nil {
   245  			log.Errorf("commit statedb error: %v", err)
   246  		}
   247  		delete(pd.dirtyset, addr)
   248  	}
   249  	// commit current trie into triedb.
   250  	rootHash, err := pd.trie.Commit(func(leaf []byte, parent ogTypes.Hash) error {
   251  		account := NewAccountData()
   252  		if _, err := account.UnmarshalMsg(leaf); err != nil {
   253  			return nil
   254  		}
   255  		// log.Tracef("onleaf called with address: %s, root: %v, codehash: %v", account.Address.Hex(), account.Root.ToBytes(), account.CodeHash)
   256  		if account.Root != emptyStateRoot {
   257  			//
   258  			//pd.db.TrieDB().Reference(account.Root, parent)
   259  		}
   260  		codehash := ogTypes.BytesToHash32(account.CodeHash)
   261  		if codehash.Cmp(emptyCodeHash) != 0 {
   262  			//pd.db.TrieDB().Reference(codehash, parent)
   263  		}
   264  		return nil
   265  	}, true)
   266  
   267  	//if trie commit fail ,nil root will write to db
   268  	if err != nil {
   269  		log.WithError(err).Warning("commit trie error")
   270  	}
   271  	log.WithField("rootHash", rootHash).Trace("state root set to")
   272  	pd.root = rootHash
   273  
   274  	pd.Reset()
   275  	return rootHash, err
   276  }
   277  
   278  func (pd *PreloadDB) AppendJournal(entry JournalEntry) {
   279  	pd.journal.append(entry)
   280  }
   281  
   282  func (pd *PreloadDB) Suicide(addr ogTypes.Address) bool {
   283  	state := pd.getStateObject(addr)
   284  	if state == nil {
   285  		return false
   286  	}
   287  	pd.AppendJournal(&suicideChange{
   288  		account:     addr,
   289  		prev:        state.suicided,
   290  		prevbalance: state.data.Balances.Copy(),
   291  	})
   292  	state.suicided = true
   293  	state.data.Balances = NewBalanceSet()
   294  	return true
   295  }
   296  
   297  func (pd *PreloadDB) HasSuicided(addr ogTypes.Address) bool {
   298  	state := pd.getStateObject(addr)
   299  	if state == nil {
   300  		return false
   301  	}
   302  	return state.suicided
   303  }
   304  
   305  // Exist reports whether the given account exists in state.
   306  // Notably this should also return true for suicided accounts.
   307  func (pd *PreloadDB) Exist(addr ogTypes.Address) bool {
   308  	if state := pd.getStateObject(addr); state != nil {
   309  		return true
   310  	}
   311  	return false
   312  }
   313  
   314  // Empty returns whether the given account is empty. Empty
   315  // is defined according to EIP161 (balance = nonce = code = 0).
   316  func (pd *PreloadDB) Empty(addr ogTypes.Address) bool {
   317  	state := pd.getStateObject(addr)
   318  	if state == nil {
   319  		return true
   320  	}
   321  	if len(state.code) != 0 {
   322  		return false
   323  	}
   324  	if state.data.Nonce != uint64(0) {
   325  		return false
   326  	}
   327  	if state.data.Balances.IsEmpty() {
   328  		return false
   329  	}
   330  	return true
   331  }
   332  
   333  // RevertToSnapshot reverts all state changes made since the given revision.
   334  func (pd *PreloadDB) RevertToSnapshot(int) {}
   335  
   336  // Snapshot creates a new revision
   337  func (pd *PreloadDB) Snapshot() int {
   338  	return 0
   339  }
   340  
   341  func (pd *PreloadDB) AddLog(l *vmtypes.Log)           {}
   342  func (pd *PreloadDB) AddPreimage(ogTypes.Hash, []byte) {}
   343  
   344  func (pd *PreloadDB) ForEachStorage(ogTypes.Address, func(ogTypes.Hash, ogTypes.Hash) bool) {}
   345  
   346  // for debug.
   347  func (pd *PreloadDB) String() string {
   348  	return ""
   349  }