Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add withdraw-keeper draft skeleton #20

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,3 +475,20 @@ func (d *Decimal) UnmarshalJSON(input []byte) error {
return err
}
}

// Result structs for GetProof
type AccountResult struct {
Address Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *hexutil.Big `json:"balance"`
CodeHash Hash `json:"codeHash"`
Nonce hexutil.Uint64 `json:"nonce"`
StorageHash Hash `json:"storageHash"`
StorageProof []StorageResult `json:"storageProof"`
}

type StorageResult struct {
Key string `json:"key"`
Value *hexutil.Big `json:"value"`
Proof []string `json:"proof"`
}
49 changes: 29 additions & 20 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
Expand Down Expand Up @@ -83,13 +84,13 @@ var (
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)

blockWriteExternalTimer = metrics.NewRegisteredTimer("chain/block/write/external", nil)
stateCommitExternalTimer = metrics.NewRegisteredTimer("chain/state/commit/external", nil)
blockWriteExternalTimer = metrics.NewRegisteredTimer("chain/block/write/external", nil)
stateCommitExternalTimer = metrics.NewRegisteredTimer("chain/state/commit/external", nil)
triedbCommitExternalTimer = metrics.NewRegisteredTimer("chain/triedb/commit/external", nil)
innerExecutionTimer = metrics.NewRegisteredTimer("chain/inner/execution", nil)
innerExecutionTimer = metrics.NewRegisteredTimer("chain/inner/execution", nil)

blockGasUsedGauge = metrics.NewRegisteredGauge("chain/block/gas/used", nil)
mgaspsGauge = metrics.NewRegisteredGauge("chain/mgas/ps", nil)
mgaspsGauge = metrics.NewRegisteredGauge("chain/mgas/ps", nil)

blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
Expand Down Expand Up @@ -160,6 +161,9 @@ type CacheConfig struct {
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it

TrieCommitInterval uint64 // Define a block height interval, commit trie every TrieCommitInterval block height.

// propose withdraw proof keeper
RpcClient *rpc.Client
}

// triedbConfig derives the configures for trie database.
Expand All @@ -177,6 +181,7 @@ func (c *CacheConfig) triedbConfig() *trie.Config {
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024,
ProposeBlockInterval: c.ProposeBlockInterval,
RpcClient: c.RpcClient,
}
}
return config
Expand Down Expand Up @@ -313,7 +318,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triedb: triedb,
triedb: triedb, //
triegc: prque.New[int64, common.Hash](nil),
quit: make(chan struct{}),
chainmu: syncx.NewClosableMutex(),
Expand Down Expand Up @@ -1460,7 +1465,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}
blockWriteExternalTimer.UpdateSince(start)
log.Debug("blockWriteExternalTimer", "duration", common.PrettyDuration(time.Since(start)), "hash", block.Hash())


// todo

// Commit all cached state changes into underlying memory database.
start = time.Now()
root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
Expand All @@ -1469,6 +1476,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}
stateCommitExternalTimer.UpdateSince(start)
log.Debug("stateCommitExternalTimer", "duration", common.PrettyDuration(time.Since(start)), "hash", block.Hash())
// todo:
// keep the proof

// If node is running in path mode, skip explicit gc operation
// which is unnecessary in this mode.
Expand All @@ -1477,10 +1486,10 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}
// If we're running an archive node, always flush
start = time.Now()
defer func () {
defer func() {
triedbCommitExternalTimer.UpdateSince(start)
log.Debug("triedbCommitExternalTimer", "duration", common.PrettyDuration(time.Since(start)), "hash", block.Hash())
} ()
}()
if bc.cacheConfig.TrieDirtyDisabled {
return bc.triedb.Commit(root, false)
}
Expand Down Expand Up @@ -1785,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
}
}()

defer func () {
defer func() {
DebugInnerExecutionDuration = 0
}()
for ; block != nil && err == nil || errors.Is(err, ErrKnownBlock); block, err = it.next() {
Expand Down Expand Up @@ -1908,16 +1917,16 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
proctime := time.Since(start) // processing + validation

// Update the metrics touched during block processing and validation
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
blockExecutionTimer.Update(ptime) // The time spent on block execution
blockValidationTimer.Update(vtime) // The time spent on block validation
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
blockExecutionTimer.Update(ptime) // The time spent on block execution
blockValidationTimer.Update(vtime) // The time spent on block validation

innerExecutionTimer.Update(DebugInnerExecutionDuration)

Expand Down Expand Up @@ -1959,7 +1968,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
}
trieDiffNodes, trieBufNodes, trieImmutableBufNodes, _ := bc.triedb.Size()
stats.report(chain, it.index, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, trieImmutableBufNodes, setHead)
blockGasUsedGauge.Update(int64(block.GasUsed())/1000000)
blockGasUsedGauge.Update(int64(block.GasUsed()) / 1000000)

if !setHead {
// After merge we expect few side chains. Simply count
Expand Down
57 changes: 57 additions & 0 deletions core/rawdb/accessors_proof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package rawdb

import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)

func WriteProof(db ethdb.AncientWriter, id uint64, proof []byte) {
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
op.AppendRaw(proposeProofTable, id-1, proof)
return nil
})
}

// ReadLatestProof is used to read the latest proof
func ReadLatestProof(f *ResettableFreezer) []byte {
proofTable := f.freezer.tables[proposeProofTable]
if proofTable == nil {
return nil
}
blob, err := f.Ancient(proposeProofTable, proofTable.items.Load())
if err != nil {
return nil
}
return blob
}

func ReadProof(f *ResettableFreezer, proofID uint64) []byte {
proofTable := f.freezer.tables[proposeProofTable]
if proofTable == nil {
return nil
}
blob, err := f.Ancient(proposeProofTable, proofID)
if err != nil {
return nil
}
return blob
}

func TruncateProofHead(f *ResettableFreezer, proofID uint64) {
f.freezer.TruncateHead(proofID)
}

// WriteKeeperMeta xx
func WriteKeeperMeta(db ethdb.KeyValueWriter, blockID uint64, meta []byte) {
key := proofKeeperMetaKey(blockID)
if err := db.Put(key, meta); err != nil {
log.Crit("Failed to store keeper meta", "err", err)
}
}

// DeleteKeeperMeta xx
func DeleteKeeperMeta(db ethdb.KeyValueWriter, blockID uint64) {
if err := db.Delete(proofKeeperMetaKey(blockID)); err != nil {
log.Crit("Failed to delete keeper meta", "err", err)
}
}
22 changes: 21 additions & 1 deletion core/rawdb/ancient_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,36 @@ var stateFreezerNoSnappy = map[string]bool{
stateHistoryStorageData: false,
}

const (
proposeProofTable = "propose_proof"
)

var proofFreezerNoSnappy = map[string]bool{
proposeProofTable: true,
}

// The list of identifiers of ancient stores.
var (
chainFreezerName = "chain" // the folder name of chain segment ancient store.
stateFreezerName = "state" // the folder name of reverse diff ancient store.
proofFreezerName = "proof" // the folder name of propose withdraw proof store
)

// freezers the collections of all builtin freezers.
var freezers = []string{chainFreezerName, stateFreezerName}
var freezers = []string{chainFreezerName, stateFreezerName, proofFreezerName}

// NewChainFreezer is a small utility method around NewFreezer that sets the
// default parameters for the chain storage.
func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) {
return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
}

// NewStateFreezer initializes the freezer for state history.
func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
return NewResettableFreezer(filepath.Join(ancientDir, stateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
}

// NewProofFreezer initializes the freezer for propose withdraw proof.
func NewProofFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
return NewResettableFreezer(filepath.Join(ancientDir, proofFreezerName), "eth/db/proof", readOnly, stateHistoryTableSize, proofFreezerNoSnappy)
}
1 change: 1 addition & 0 deletions core/rawdb/ancient_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
return nil, err
}
infos = append(infos, info)
// todo:

default:
return nil, fmt.Errorf("unknown freezer, supported ones: %v", freezers)
Expand Down
6 changes: 0 additions & 6 deletions core/rawdb/freezer.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,6 @@ type Freezer struct {
closeOnce sync.Once
}

// NewChainFreezer is a small utility method around NewFreezer that sets the
// default parameters for the chain storage.
func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) {
return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
}

// NewFreezer creates a freezer instance for maintaining immutable ordered
// data according to the given parameters.
//
Expand Down
8 changes: 8 additions & 0 deletions core/rawdb/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ var (
trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id

// todo: keeper meta
ProofKeeperMetaPrefix = []byte("p") // proofKeeperMetaPrefix + num (uint64 big endian) -> proof keeper meta

PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db
Expand Down Expand Up @@ -156,6 +159,11 @@ func headerKeyPrefix(number uint64) []byte {
return append(headerPrefix, encodeBlockNumber(number)...)
}

// proofKeeperMetaKey = ProofKeeperMetaPrefix + num (uint64 big endian)
func proofKeeperMetaKey(number uint64) []byte {
return append(ProofKeeperMetaPrefix, encodeBlockNumber(number)...)
}

// headerKey = headerPrefix + num (uint64 big endian) + hash
func headerKey(number uint64, hash common.Hash) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
Expand Down
5 changes: 5 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
)

// EthAPIBackend implements ethapi.Backend and tracers.Backend for full nodes
Expand All @@ -54,6 +55,10 @@ type EthAPIBackend struct {
gpo *gasprice.Oracle
}

func (b *EthAPIBackend) TrieDatabase() *trie.Database {
return b.eth.blockchain.TrieDB()
}

// ChainConfig returns the active chain configuration.
func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
return b.eth.blockchain.Config()
Expand Down
8 changes: 5 additions & 3 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ type Ethereum struct {
networkID uint64
netRPCService *ethapi.NetAPI

p2pServer *p2p.Server
p2pServer *p2p.Server // todo

lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)

Expand Down Expand Up @@ -209,6 +209,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
TrieCommitInterval: config.TrieCommitInterval,
PathNodeBuffer: config.PathNodeBuffer,
ProposeBlockInterval: config.ProposeBlockInterval,
// todo
RpcClient: stack.Attach(),
}
)
// Override the chain config with provided settings.
Expand Down Expand Up @@ -319,7 +321,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {

// Register the backend on the node
stack.RegisterAPIs(eth.APIs())
stack.RegisterProtocols(eth.Protocols())
stack.RegisterProtocols(eth.Protocols()) // todo
stack.RegisterLifecycle(eth)

// Successful startup; push a marker and check previous unclean shutdowns.
Expand Down Expand Up @@ -535,7 +537,7 @@ func (s *Ethereum) SyncMode() downloader.SyncMode {

// Protocols returns all the currently configured
// network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol {
func (s *Ethereum) Protocols() []p2p.Protocol { // todo
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates)
if s.config.SnapshotCache > 0 {
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
Expand Down
21 changes: 21 additions & 0 deletions ethclient/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ func (ec *Client) Client() *rpc.Client {
return ec.c
}

// todo:
func (ec *Client) GetProof(ctx context.Context, address common.Address, storage []common.Hash, blockTag string) (*common.AccountResult, error) {
var getProofResponse *common.AccountResult
err := ec.c.CallContext(ctx, &getProofResponse, "eth_getProof", address, storage, blockTag)
if err != nil {
return nil, err
}
if getProofResponse == nil {
return nil, ethereum.NotFound
}
if len(getProofResponse.StorageProof) != len(storage) {
return nil, fmt.Errorf("missing storage proof data, got %d proof entries but requested %d storage keys", len(getProofResponse.StorageProof), len(storage))
}
for i, key := range storage {
if key.String() != getProofResponse.StorageProof[i].Key {
return nil, fmt.Errorf("unexpected storage proof key difference for entry %d: got %s but requested %s", i, getProofResponse.StorageProof[i].Key, key)
}
}
return getProofResponse, nil
}

// Blockchain Access

// ChainID retrieves the current chain ID for transaction replay protection.
Expand Down
Loading
Loading