Finish state object implementation
This commit is contained in:
parent
be81045e26
commit
b77d74f405
@ -52,21 +52,9 @@ type (
|
|||||||
suicided bool
|
suicided bool
|
||||||
deleted bool
|
deleted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Account is the Ethereum consensus representation of accounts.
|
|
||||||
// // These objects are stored in the main account trie.
|
|
||||||
// Account struct {
|
|
||||||
// Nonce uint64
|
|
||||||
// Balance *big.Int
|
|
||||||
// Root ethcmn.Hash // merkle root of the storage trie
|
|
||||||
// CodeHash []byte
|
|
||||||
// }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newObject(db *CommitStateDB, accProto auth.Account) *stateObject {
|
func newObject(db *CommitStateDB, accProto auth.Account) *stateObject {
|
||||||
// if acc.Balance == nil {
|
|
||||||
// data.Balance = new(big.Int)
|
|
||||||
// }
|
|
||||||
acc, ok := accProto.(*types.Account)
|
acc, ok := accProto.(*types.Account)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("invalid account type for state object: %T", acc))
|
panic(fmt.Sprintf("invalid account type for state object: %T", acc))
|
||||||
@ -85,13 +73,9 @@ func newObject(db *CommitStateDB, accProto auth.Account) *stateObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address returns the address of the state object.
|
// GetState retrieves a value from the account storage trie. Note, the key must
|
||||||
func (so stateObject) Address() ethcmn.Address {
|
// be prefixed with the address.
|
||||||
return so.address
|
func (so *stateObject) GetState(_ ethstate.Database, key ethcmn.Hash) ethcmn.Hash {
|
||||||
}
|
|
||||||
|
|
||||||
// GetState retrieves a value from the account storage trie.
|
|
||||||
func (so *stateObject) GetState(_ Database, key ethcmn.Hash) ethcmn.Hash {
|
|
||||||
// if we have a dirty value for this state entry, return it
|
// if we have a dirty value for this state entry, return it
|
||||||
value, dirty := so.dirtyStorage[key]
|
value, dirty := so.dirtyStorage[key]
|
||||||
if dirty {
|
if dirty {
|
||||||
@ -99,11 +83,33 @@ func (so *stateObject) GetState(_ Database, key ethcmn.Hash) ethcmn.Hash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// otherwise return the entry's original value
|
// otherwise return the entry's original value
|
||||||
return so.getCommittedState(key)
|
return so.getCommittedState(so.stateDB.ctx, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetState updates a value in account storage.
|
// GetCommittedState retrieves a value from the committed account storage trie.
|
||||||
func (so *stateObject) SetState(db Database, key, value ethcmn.Hash) {
|
// Note, the must be prefixed with the address.
|
||||||
|
func (so *stateObject) getCommittedState(ctx sdk.Context, key ethcmn.Hash) ethcmn.Hash {
|
||||||
|
// if we have the original value cached, return that
|
||||||
|
value, cached := so.originStorage[key]
|
||||||
|
if cached {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise load the value from the KVStore
|
||||||
|
store := ctx.KVStore(so.stateDB.storageKey)
|
||||||
|
rawValue := store.Get(key.Bytes())
|
||||||
|
|
||||||
|
if len(rawValue) > 0 {
|
||||||
|
value.SetBytes(rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
so.originStorage[key] = value
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetState updates a value in account storage. Note, the key must be prefixed
|
||||||
|
// with the address.
|
||||||
|
func (so *stateObject) SetState(db ethstate.Database, key, value ethcmn.Hash) {
|
||||||
// if the new value is the same as old, don't set
|
// if the new value is the same as old, don't set
|
||||||
prev := so.GetState(db, key)
|
prev := so.GetState(db, key)
|
||||||
if prev == value {
|
if prev == value {
|
||||||
@ -120,6 +126,50 @@ func (so *stateObject) SetState(db Database, key, value ethcmn.Hash) {
|
|||||||
so.setState(key, value)
|
so.setState(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (so *stateObject) setState(key, value ethcmn.Hash) {
|
||||||
|
so.dirtyStorage[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code returns the contract code associated with this object, if any.
|
||||||
|
func (so *stateObject) Code(_ ethstate.Database) []byte {
|
||||||
|
if so.code != nil {
|
||||||
|
return so.code
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(so.CodeHash(), emptyCodeHash) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
store := so.stateDB.ctx.KVStore(so.stateDB.codeKey)
|
||||||
|
code := store.Get(so.CodeHash())
|
||||||
|
|
||||||
|
if len(code) == 0 {
|
||||||
|
so.setError(fmt.Errorf("failed to get code hash %x for address: %x", so.CodeHash(), so.Address()))
|
||||||
|
}
|
||||||
|
|
||||||
|
so.code = code
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCode sets the state object's code.
|
||||||
|
func (so *stateObject) SetCode(codeHash ethcmn.Hash, code []byte) {
|
||||||
|
prevcode := so.Code(nil)
|
||||||
|
|
||||||
|
so.stateDB.journal.append(codeChange{
|
||||||
|
account: &so.address,
|
||||||
|
prevhash: so.CodeHash(),
|
||||||
|
prevcode: prevcode,
|
||||||
|
})
|
||||||
|
|
||||||
|
so.setCode(codeHash, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (so *stateObject) setCode(codeHash ethcmn.Hash, code []byte) {
|
||||||
|
so.code = code
|
||||||
|
so.account.CodeHash = codeHash.Bytes()
|
||||||
|
so.dirtyCode = true
|
||||||
|
}
|
||||||
|
|
||||||
// AddBalance adds an amount to a state object's balance. It is used to add
|
// AddBalance adds an amount to a state object's balance. It is used to add
|
||||||
// funds to the destination account of a transfer.
|
// funds to the destination account of a transfer.
|
||||||
func (so *stateObject) AddBalance(amount *big.Int) {
|
func (so *stateObject) AddBalance(amount *big.Int) {
|
||||||
@ -139,6 +189,20 @@ func (so *stateObject) AddBalance(amount *big.Int) {
|
|||||||
so.SetBalance(newBalance.BigInt())
|
so.SetBalance(newBalance.BigInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubBalance removes an amount from the stateObject's balance. It is used to
|
||||||
|
// remove funds from the origin account of a transfer.
|
||||||
|
func (so *stateObject) SubBalance(amount *big.Int) {
|
||||||
|
amt := sdk.NewIntFromBigInt(amount)
|
||||||
|
|
||||||
|
if amt.Sign() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newBalance := so.account.Balance().Sub(amt)
|
||||||
|
so.SetBalance(newBalance.BigInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBalance sets the state object's balance.
|
||||||
func (so *stateObject) SetBalance(amount *big.Int) {
|
func (so *stateObject) SetBalance(amount *big.Int) {
|
||||||
amt := sdk.NewIntFromBigInt(amount)
|
amt := sdk.NewIntFromBigInt(amount)
|
||||||
|
|
||||||
@ -150,74 +214,46 @@ func (so *stateObject) SetBalance(amount *big.Int) {
|
|||||||
so.setBalance(amt)
|
so.setBalance(amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubBalance removes amount from c's balance.
|
|
||||||
// It is used to remove funds from the origin account of a transfer.
|
|
||||||
func (so *stateObject) SubBalance(amount *big.Int) {
|
|
||||||
if amount.Sign() == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.SetBalance(new(big.Int).Sub(c.Balance(), amount))
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (so *stateObject) Balance() *big.Int {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) ReturnGas(gas *big.Int) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) Address() ethcmn.Address {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) SetCode(codeHash ethcmn.Hash, code []byte) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) SetNonce(nonce uint64) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) Nonce() uint64 {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) Code(db Database) []byte {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (so *stateObject) CodeHash() []byte {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (so *stateObject) setBalance(amount sdk.Int) {
|
func (so *stateObject) setBalance(amount sdk.Int) {
|
||||||
so.account.SetBalance(amount)
|
so.account.SetBalance(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommittedState retrieves a value from the committed account storage trie.
|
// Balance returns the state object's current balance.
|
||||||
func (so *stateObject) getCommittedState(key ethcmn.Hash) ethcmn.Hash {
|
func (so *stateObject) Balance() *big.Int {
|
||||||
// if we have the original value cached, return that
|
return so.account.Balance().BigInt()
|
||||||
value, cached := so.originStorage[key]
|
|
||||||
if cached {
|
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise load the value from the KVStore
|
// ReturnGas returns the gas back to the origin. Used by the Virtual machine or
|
||||||
store := so.stateDB.ctx.KVStore(so.stateDB.storageKey)
|
// Closures. It performs a no-op.
|
||||||
rawValue := store.Get(key.Bytes())
|
func (so *stateObject) ReturnGas(gas *big.Int) {}
|
||||||
|
|
||||||
if len(rawValue) > 0 {
|
// Address returns the address of the state object.
|
||||||
value.SetBytes(rawValue)
|
func (so stateObject) Address() ethcmn.Address {
|
||||||
|
return so.address
|
||||||
}
|
}
|
||||||
|
|
||||||
so.originStorage[key] = value
|
// CodeHash returns the state object's code hash.
|
||||||
return value
|
func (so *stateObject) CodeHash() []byte {
|
||||||
|
return so.account.CodeHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *stateObject) setState(key, value ethcmn.Hash) {
|
// Nonce returns the state object's current nonce (sequence number).
|
||||||
so.dirtyStorage[key] = value
|
func (so *stateObject) Nonce() uint64 {
|
||||||
|
return uint64(so.account.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNonce sets the state object's nonce (sequence number).
|
||||||
|
func (so *stateObject) SetNonce(nonce uint64) {
|
||||||
|
so.stateDB.journal.append(nonceChange{
|
||||||
|
account: &so.address,
|
||||||
|
prev: so.account.Sequence,
|
||||||
|
})
|
||||||
|
|
||||||
|
so.setNonce(int64(nonce))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (so *stateObject) setNonce(nonce int64) {
|
||||||
|
so.account.Sequence = nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// setError remembers the first non-nil error it is called with.
|
// setError remembers the first non-nil error it is called with.
|
||||||
@ -245,3 +281,14 @@ func (so *stateObject) touch() {
|
|||||||
so.stateDB.journal.dirty(so.address)
|
so.stateDB.journal.dirty(so.address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prefixStorageKey prefixes a storage key with the state object's address.
|
||||||
|
func (so stateObject) prefixStorageKey(key []byte) []byte {
|
||||||
|
prefix := so.Address().Bytes()
|
||||||
|
compositeKey := make([]byte, len(prefix)+len(key))
|
||||||
|
|
||||||
|
copy(compositeKey, prefix)
|
||||||
|
copy(compositeKey[len(prefix):], key)
|
||||||
|
|
||||||
|
return compositeKey
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user