Unverified Commit 0e5d2c7c authored by rjl493456442's avatar rjl493456442 Committed by GitHub

core/state/snapshot, core/types, eth: move account definition to type (#27323)

* core/state/snapshot, core/types, eth: move account definition to type

* core, eth: revert snapshot Account API change
parent c537ace2
......@@ -517,14 +517,14 @@ func dumpState(ctx *cli.Context) error {
Root common.Hash `json:"root"`
}{root})
for accIt.Next() {
account, err := snapshot.FullAccount(accIt.Account())
account, err := types.FullAccount(accIt.Account())
if err != nil {
return err
}
da := &state.DumpAccount{
Balance: account.Balance.String(),
Nonce: account.Nonce,
Root: account.Root,
Root: account.Root.Bytes(),
CodeHash: account.CodeHash,
SecureKey: accIt.Hash().Bytes(),
}
......
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package snapshot
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
// Account is a modified version of a state.Account, where the root is replaced
// with a byte slice. This format can be used to represent full-consensus format
// or slim-snapshot format which replaces the empty root and code hash as nil
// byte slice.
type Account struct {
Nonce uint64
Balance *big.Int
Root []byte
CodeHash []byte
}
// SlimAccount converts a state.Account content into a slim snapshot account
func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []byte) Account {
slim := Account{
Nonce: nonce,
Balance: balance,
}
if root != types.EmptyRootHash {
slim.Root = root[:]
}
if !bytes.Equal(codehash, types.EmptyCodeHash[:]) {
slim.CodeHash = codehash
}
return slim
}
// SlimAccountRLP converts a state.Account content into a slim snapshot
// version RLP encoded.
func SlimAccountRLP(nonce uint64, balance *big.Int, root common.Hash, codehash []byte) []byte {
data, err := rlp.EncodeToBytes(SlimAccount(nonce, balance, root, codehash))
if err != nil {
panic(err)
}
return data
}
// FullAccount decodes the data on the 'slim RLP' format and return
// the consensus format account.
func FullAccount(data []byte) (Account, error) {
var account Account
if err := rlp.DecodeBytes(data, &account); err != nil {
return Account{}, err
}
if len(account.Root) == 0 {
account.Root = types.EmptyRootHash[:]
}
if len(account.CodeHash) == 0 {
account.CodeHash = types.EmptyCodeHash[:]
}
return account, nil
}
// FullAccountRLP converts data on the 'slim RLP' format into the full RLP-format.
func FullAccountRLP(data []byte) ([]byte, error) {
account, err := FullAccount(data)
if err != nil {
return nil, err
}
return rlp.EncodeToBytes(account)
}
......@@ -17,7 +17,6 @@
package snapshot
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
......@@ -301,7 +300,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou
fullData []byte
)
if leafCallback == nil {
fullData, err = FullAccountRLP(it.(AccountIterator).Account())
fullData, err = types.FullAccountRLP(it.(AccountIterator).Account())
if err != nil {
return stop(err)
}
......@@ -313,7 +312,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou
return stop(err)
}
// Fetch the next account and process it concurrently
account, err := FullAccount(it.(AccountIterator).Account())
account, err := types.FullAccount(it.(AccountIterator).Account())
if err != nil {
return stop(err)
}
......@@ -323,7 +322,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, accou
results <- err
return
}
if !bytes.Equal(account.Root, subroot.Bytes()) {
if account.Root != subroot {
results <- fmt.Errorf("invalid subroot(path %x), want %x, have %x", hash, account.Root, subroot)
return
}
......
......@@ -27,6 +27,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
bloomfilter "github.com/holiman/bloomfilter/v2"
)
......@@ -272,7 +273,7 @@ func (dl *diffLayer) Stale() bool {
// Account directly retrieves the account associated with a particular hash in
// the snapshot slim data format.
func (dl *diffLayer) Account(hash common.Hash) (*Account, error) {
func (dl *diffLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
data, err := dl.AccountRLP(hash)
if err != nil {
return nil, err
......@@ -280,7 +281,7 @@ func (dl *diffLayer) Account(hash common.Hash) (*Account, error) {
if len(data) == 0 { // can be both nil and []byte{}
return nil, nil
}
account := new(Account)
account := new(types.SlimAccount)
if err := rlp.DecodeBytes(data, account); err != nil {
panic(err)
}
......@@ -292,8 +293,8 @@ func (dl *diffLayer) Account(hash common.Hash) (*Account, error) {
//
// Note the returned account is not a copy, please don't modify it.
func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) {
dl.lock.RLock()
// Check staleness before reaching further.
dl.lock.RLock()
if dl.Stale() {
dl.lock.RUnlock()
return nil, ErrSnapshotStale
......
......@@ -23,6 +23,7 @@ import (
"github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
......@@ -65,7 +66,7 @@ func (dl *diskLayer) Stale() bool {
// Account directly retrieves the account associated with a particular hash in
// the snapshot slim data format.
func (dl *diskLayer) Account(hash common.Hash) (*Account, error) {
func (dl *diskLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
data, err := dl.AccountRLP(hash)
if err != nil {
return nil, err
......@@ -73,7 +74,7 @@ func (dl *diskLayer) Account(hash common.Hash) (*Account, error) {
if len(data) == 0 { // can be both nil and []byte{}
return nil, nil
}
account := new(Account)
account := new(types.SlimAccount)
if err := rlp.DecodeBytes(data, account); err != nil {
panic(err)
}
......
......@@ -20,7 +20,6 @@ import (
"bytes"
"errors"
"fmt"
"math/big"
"time"
"github.com/VictoriaMetrics/fastcache"
......@@ -573,12 +572,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
return nil
}
// Retrieve the current account and flatten it into the internal format
var acc struct {
Nonce uint64
Balance *big.Int
Root common.Hash
CodeHash []byte
}
var acc types.StateAccount
if err := rlp.DecodeBytes(val, &acc); err != nil {
log.Crit("Invalid account encountered during snapshot creation", "err", err)
}
......@@ -594,7 +588,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
}
snapRecoveredAccountMeter.Mark(1)
} else {
data := SlimAccountRLP(acc.Nonce, acc.Balance, acc.Root, acc.CodeHash)
data := types.SlimAccountRLP(acc)
dataLen = len(data)
rawdb.WriteAccountSnapshot(ctx.batch, account, data)
snapGeneratedAccountMeter.Mark(1)
......@@ -640,7 +634,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
origin := common.CopyBytes(accMarker)
for {
id := trie.StateTrieID(dl.root)
exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, FullAccountRLP)
exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP)
if err != nil {
return err // The procedure it aborted, either by external signal or internal error.
}
......
This diff is collapsed.
......@@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
......@@ -102,7 +103,7 @@ type Snapshot interface {
// Account directly retrieves the account associated with a particular hash in
// the snapshot slim data format.
Account(hash common.Hash) (*Account, error)
Account(hash common.Hash) (*types.SlimAccount, error)
// AccountRLP directly retrieves the account RLP associated with a particular
// hash in the snapshot slim data format.
......
......@@ -43,11 +43,10 @@ func randomHash() common.Hash {
// randomAccount generates a random account and returns it RLP encoded.
func randomAccount() []byte {
root := randomHash()
a := Account{
a := &types.StateAccount{
Balance: big.NewInt(rand.Int63()),
Nonce: rand.Uint64(),
Root: root[:],
Root: randomHash(),
CodeHash: types.EmptyCodeHash[:],
}
data, _ := rlp.EncodeToBytes(a)
......@@ -465,7 +464,7 @@ func TestReadStateDuringFlattening(t *testing.T) {
snap := snaps.Snapshot(common.HexToHash("0xa3"))
// Register the testing hook to access the state after flattening
var result = make(chan *Account)
var result = make(chan *types.SlimAccount)
snaps.onFlatten = func() {
// Spin up a thread to read the account from the pre-created
// snapshot handler. It's expected to be blocked.
......
......@@ -23,9 +23,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// CheckDanglingStorage iterates the snap storage data, and verifies that all
......@@ -98,8 +98,8 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error {
baseRoot := rawdb.ReadSnapshotRoot(db)
fmt.Printf("Disklayer: Root: %x\n", baseRoot)
if data := rawdb.ReadAccountSnapshot(db, hash); data != nil {
account := new(Account)
if err := rlp.DecodeBytes(data, account); err != nil {
account, err := types.FullAccount(data)
if err != nil {
panic(err)
}
fmt.Printf("\taccount.nonce: %d\n", account.Nonce)
......@@ -129,8 +129,8 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error {
}
fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot)
if data, ok := accounts[hash]; ok {
account := new(Account)
if err := rlp.DecodeBytes(data, account); err != nil {
account, err := types.FullAccount(data)
if err != nil {
panic(err)
}
fmt.Printf("\taccount.nonce: %d\n", account.Nonce)
......
......@@ -522,7 +522,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
// enough to track account updates at commit time, deletions need tracking
// at transaction boundary level to ensure we capture state clearing.
if s.snap != nil {
s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash)
s.snapAccounts[obj.addrHash] = types.SlimAccountRLP(obj.data)
}
}
......
......@@ -17,9 +17,11 @@
package types
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)
//go:generate go run ../../rlp/rlpgen -type StateAccount -out gen_account_rlp.go
......@@ -32,3 +34,65 @@ type StateAccount struct {
Root common.Hash // merkle root of the storage trie
CodeHash []byte
}
// SlimAccount is a modified version of an Account, where the root is replaced
// with a byte slice. This format can be used to represent full-consensus format
// or slim format which replaces the empty root and code hash as nil byte slice.
type SlimAccount struct {
Nonce uint64
Balance *big.Int
Root []byte // Nil if root equals to types.EmptyRootHash
CodeHash []byte // Nil if hash equals to types.EmptyCodeHash
}
// SlimAccountRLP encodes the state account in 'slim RLP' format.
func SlimAccountRLP(account StateAccount) []byte {
slim := SlimAccount{
Nonce: account.Nonce,
Balance: account.Balance,
}
if account.Root != EmptyRootHash {
slim.Root = account.Root[:]
}
if !bytes.Equal(account.CodeHash, EmptyCodeHash[:]) {
slim.CodeHash = account.CodeHash
}
data, err := rlp.EncodeToBytes(slim)
if err != nil {
panic(err)
}
return data
}
// FullAccount decodes the data on the 'slim RLP' format and return
// the consensus format account.
func FullAccount(data []byte) (*StateAccount, error) {
var slim SlimAccount
if err := rlp.DecodeBytes(data, &slim); err != nil {
return nil, err
}
var account StateAccount
account.Nonce, account.Balance = slim.Nonce, slim.Balance
// Interpret the storage root and code hash in slim format.
if len(slim.Root) == 0 {
account.Root = EmptyRootHash
} else {
account.Root = common.BytesToHash(slim.Root)
}
if len(slim.CodeHash) == 0 {
account.CodeHash = EmptyCodeHash[:]
} else {
account.CodeHash = slim.CodeHash
}
return &account, nil
}
// FullAccountRLP converts data on the 'slim RLP' format into the full RLP-format.
func FullAccountRLP(data []byte) ([]byte, error) {
account, err := FullAccount(data)
if err != nil {
return nil, err
}
return rlp.EncodeToBytes(account)
}
......@@ -21,7 +21,7 @@ import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
......@@ -104,7 +104,7 @@ func (p *AccountRangePacket) Unpack() ([]common.Hash, [][]byte, error) {
accounts = make([][]byte, len(p.Accounts))
)
for i, acc := range p.Accounts {
val, err := snapshot.FullAccountRLP(acc.Body)
val, err := types.FullAccountRLP(acc.Body)
if err != nil {
return nil, nil, fmt.Errorf("invalid account %x: %v", acc.Body, err)
}
......
......@@ -33,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
......@@ -2277,13 +2276,13 @@ func (s *Syncer) forwardAccountTask(task *accountTask) {
if task.needCode[i] || task.needState[i] {
break
}
slim := snapshot.SlimAccountRLP(res.accounts[i].Nonce, res.accounts[i].Balance, res.accounts[i].Root, res.accounts[i].CodeHash)
slim := types.SlimAccountRLP(*res.accounts[i])
rawdb.WriteAccountSnapshot(batch, hash, slim)
// If the task is complete, drop it into the stack trie to generate
// account trie nodes for it
if !task.needHeal[i] {
full, err := snapshot.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted
full, err := types.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted
if err != nil {
panic(err) // Really shouldn't ever happen
}
......@@ -2902,7 +2901,7 @@ func (s *Syncer) onHealState(paths [][]byte, value []byte) error {
if err := rlp.DecodeBytes(value, &account); err != nil {
return nil // Returning the error here would drop the remote peer
}
blob := snapshot.SlimAccountRLP(account.Nonce, account.Balance, account.Root, account.CodeHash)
blob := types.SlimAccountRLP(account)
rawdb.WriteAccountSnapshot(s.stateWriter, common.BytesToHash(paths[0]), blob)
s.accountHealed += 1
s.accountHealedBytes += common.StorageSize(1 + common.HashLength + len(blob))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment