-
Notifications
You must be signed in to change notification settings - Fork 7
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
Implementation of the debug_getAccessibleState and debug_dbGet methods #398
base: develop
Are you sure you want to change the base?
Changes from all commits
0d9120f
67fe90c
1af8f93
a6ca1b7
66eda70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"context" | ||
"errors" | ||
"fmt" | ||
"math" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
|
@@ -55,6 +56,13 @@ type debugBlockchainStore interface { | |
// GetPendingTx returns the transaction by hash in the TxPool (pending txn) [Thread-safe] | ||
GetPendingTx(txHash types.Hash) (*types.Transaction, bool) | ||
|
||
// Has returns true if the DB does contains the given key. | ||
Has(hashRoot types.Hash) bool | ||
|
||
// Get gets the value for the given key. It returns ErrNotFound if the | ||
// DB does not contains the key. | ||
Get(key string) ([]byte, error) | ||
|
||
// GetIteratorDumpTree returns a set of accounts based on the given criteria and depends on the starting element. | ||
GetIteratorDumpTree(block *types.Block, opts *state.DumpInfo) (*state.IteratorDump, error) | ||
|
||
|
@@ -723,6 +731,83 @@ func (d *Debug) DumpBlock(blockNumber BlockNumber) (interface{}, error) { | |
) | ||
} | ||
|
||
// GetAccessibleState returns the first number where the node has accessible | ||
// state on disk. Note this being the post-state of that block and the pre-state | ||
// of the next block. | ||
// The (from, to) parameters are the sequence of blocks to search, which can go | ||
// either forwards or backwards | ||
func (d *Debug) GetAccessibleState(from, to BlockNumber) (interface{}, error) { | ||
return d.throttling.AttemptRequest( | ||
context.Background(), | ||
func() (interface{}, error) { | ||
getBlockNumber := func(num BlockNumber) (int64, error) { | ||
n, err := GetNumericBlockNumber(num, d.store) | ||
if err != nil { | ||
return 0, fmt.Errorf("failed to get block number: %w", err) | ||
} | ||
|
||
if n > math.MaxInt64 { | ||
return 0, fmt.Errorf("block number %d overflows int64", n) | ||
} | ||
|
||
return int64(n), nil | ||
} | ||
|
||
// Get start and end block numbers | ||
start, err := getBlockNumber(from) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
end, err := getBlockNumber(to) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
if start == end { | ||
return 0, fmt.Errorf("'from' and 'to' block numbers must be different") | ||
} | ||
|
||
delta := int64(1) | ||
if start > end { | ||
delta = -1 | ||
} | ||
|
||
for i := start; i != end; i += delta { | ||
if i < 0 { | ||
return 0, fmt.Errorf("block number overflow: %d", i) | ||
} | ||
|
||
blockNum := uint64(i) | ||
h, ok := d.store.GetHeaderByNumber(blockNum) | ||
|
||
if !ok { | ||
return 0, fmt.Errorf("missing header for block number %d", i) | ||
} | ||
|
||
if d.store.Has(h.StateRoot) { | ||
return blockNum, nil | ||
} | ||
} | ||
|
||
// No state found | ||
return 0, errors.New("no accessible state found between the given block numbers") | ||
}, | ||
) | ||
} | ||
|
||
// DbGet returns the raw value of a key stored in the database. | ||
// | ||
//nolint:stylecheck | ||
func (d *Debug) DbGet(key string) (interface{}, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return []byte instead of interface. There is a question from which database data needs to be returned, state or blockchain? IMO we should check both, but in that case we need to extend blockchain API with Get method. Although it's not complicated I am not sure if it's worth it. For now we can keep it this way, returning value only from state DB. |
||
return d.throttling.AttemptRequest( | ||
context.Background(), | ||
func() (interface{}, error) { | ||
return d.store.Get(key) | ||
}, | ||
) | ||
} | ||
|
||
func (d *Debug) traceBlock( | ||
block *types.Block, | ||
config *TraceConfig, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,6 +74,10 @@ func (s *Snapshot) GetCode(hash types.Hash) ([]byte, bool) { | |
return s.state.GetCode(hash) | ||
} | ||
|
||
func (s *Snapshot) Get(hash types.Hash) ([]byte, bool, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need for this method. |
||
return s.state.storage.Get(hash.Bytes()) | ||
} | ||
|
||
func (s *Snapshot) GetRootHash() types.Hash { | ||
tt := s.trie.Txn(s.state.storage) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ type readSnapshot interface { | |
GetStorage(addr types.Address, root types.Hash, key types.Hash) types.Hash | ||
GetAccount(addr types.Address) (*Account, error) | ||
GetCode(hash types.Hash) ([]byte, bool) | ||
Get(hash types.Hash) ([]byte, bool, error) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need for this method. |
||
GetRootHash() types.Hash | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return uint64 instead of interface