fix service.go: prevent panics on subtrie iterators with odd-length prefix-paths
This commit is contained in:
parent
3d8064ccbb
commit
4081787b03
@ -219,10 +219,10 @@ func (s *Service) createSnapshot(ctx context.Context, it trie.NodeIterator, head
|
|||||||
// end path for the concurrent iterator
|
// end path for the concurrent iterator
|
||||||
var endPath []byte
|
var endPath []byte
|
||||||
|
|
||||||
if iter, ok := it.(*trackedIter); ok {
|
if i, ok := it.(*trackedIter); ok {
|
||||||
seekedPath = &iter.seekedPath
|
seekedPath = &i.seekedPath
|
||||||
recoveredPath = append(recoveredPath, *seekedPath...)
|
recoveredPath = append(recoveredPath, *seekedPath...)
|
||||||
endPath = iter.endPath
|
endPath = i.endPath
|
||||||
} else {
|
} else {
|
||||||
return errors.New("untracked iterator")
|
return errors.New("untracked iterator")
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ func (s *Service) createSubTrieSnapshot(ctx context.Context, tx Tx, prefixPath [
|
|||||||
// if node path is empty and prefix is nil, it's the root node
|
// if node path is empty and prefix is nil, it's the root node
|
||||||
if prefixPath == nil {
|
if prefixPath == nil {
|
||||||
// create snapshot of node, if it is a leaf this will also create snapshot of entire storage trie
|
// create snapshot of node, if it is a leaf this will also create snapshot of entire storage trie
|
||||||
if err := s.createNodeSnapshot(tx, subTrieIt, headerID, height, seekingPaths); err != nil {
|
if err := s.createNodeSnapshot(tx, subTrieIt, headerID, height, seekingPaths, prefixPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
updateSeekedPath(seekedPath, subTrieIt.Path())
|
updateSeekedPath(seekedPath, subTrieIt.Path())
|
||||||
@ -307,7 +307,7 @@ func (s *Service) createSubTrieSnapshot(ctx context.Context, tx Tx, prefixPath [
|
|||||||
|
|
||||||
// if the node is along paths of interest
|
// if the node is along paths of interest
|
||||||
// create snapshot of node, if it is a leaf this will also create snapshot of entire storage trie
|
// create snapshot of node, if it is a leaf this will also create snapshot of entire storage trie
|
||||||
if err := s.createNodeSnapshot(tx, subTrieIt, headerID, height, seekingPaths); err != nil {
|
if err := s.createNodeSnapshot(tx, subTrieIt, headerID, height, seekingPaths, prefixPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// update seeked path after node has been processed
|
// update seeked path after node has been processed
|
||||||
@ -358,7 +358,8 @@ func (s *Service) createSubTrieIt(prefixPath []byte, hash common.Hash, recovered
|
|||||||
|
|
||||||
// createNodeSnapshot indexes the current node
|
// createNodeSnapshot indexes the current node
|
||||||
// entire storage trie is also indexed (if available)
|
// entire storage trie is also indexed (if available)
|
||||||
func (s *Service) createNodeSnapshot(tx Tx, it trie.NodeIterator, headerID string, height *big.Int, watchedAddressesLeafPaths [][]byte) error {
|
func (s *Service) createNodeSnapshot(tx Tx, it trie.NodeIterator, headerID string, height *big.Int,
|
||||||
|
watchedAddressesLeafPaths [][]byte, prefixPath []byte) error {
|
||||||
tx, err := s.ipfsPublisher.PrepareTxForBatch(tx, s.maxBatchSize)
|
tx, err := s.ipfsPublisher.PrepareTxForBatch(tx, s.maxBatchSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -369,7 +370,7 @@ func (s *Service) createNodeSnapshot(tx Tx, it trie.NodeIterator, headerID strin
|
|||||||
// if it is a "value" node, we will index the value by leaf key
|
// if it is a "value" node, we will index the value by leaf key
|
||||||
// publish codehash => code mappings
|
// publish codehash => code mappings
|
||||||
// take storage snapshot
|
// take storage snapshot
|
||||||
if err := s.processStateValueNode(it, headerID, height, watchedAddressesLeafPaths, tx); err != nil {
|
if err := s.processStateValueNode(it, headerID, height, prefixPath, watchedAddressesLeafPaths, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else { // trie nodes will be written to blockstore only
|
} else { // trie nodes will be written to blockstore only
|
||||||
@ -391,8 +392,8 @@ func (s *Service) createNodeSnapshot(tx Tx, it trie.NodeIterator, headerID strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
nodePath := make([]byte, len(it.Path()))
|
// create the full node path as it.Path() doesn't include the path before subtrie root
|
||||||
copy(nodePath, it.Path())
|
nodePath := append(prefixPath, it.Path()...)
|
||||||
partialPath := trie.CompactToHex(elements[0].([]byte))
|
partialPath := trie.CompactToHex(elements[0].([]byte))
|
||||||
valueNodePath := append(nodePath, partialPath...)
|
valueNodePath := append(nodePath, partialPath...)
|
||||||
if !isWatchedAddress(watchedAddressesLeafPaths, valueNodePath) {
|
if !isWatchedAddress(watchedAddressesLeafPaths, valueNodePath) {
|
||||||
@ -403,7 +404,7 @@ func (s *Service) createNodeSnapshot(tx Tx, it trie.NodeIterator, headerID strin
|
|||||||
}
|
}
|
||||||
nodeHash := make([]byte, len(it.Hash().Bytes()))
|
nodeHash := make([]byte, len(it.Hash().Bytes()))
|
||||||
copy(nodeHash, it.Hash().Bytes())
|
copy(nodeHash, it.Hash().Bytes())
|
||||||
if _, err := s.ipfsPublisher.PublishIPLD(ipld.Keccak256ToCid(ipld.MEthStateTrie, nodeHash), nodeVal, height, tx); err != nil {
|
if err := s.ipfsPublisher.PublishIPLD(ipld.Keccak256ToCid(ipld.MEthStateTrie, nodeHash), nodeVal, height, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,11 +413,13 @@ func (s *Service) createNodeSnapshot(tx Tx, it trie.NodeIterator, headerID strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reminder: it.Leaf() == true when the iterator is positioned at a "value node" which is not something that actually exists in an MMPT
|
// reminder: it.Leaf() == true when the iterator is positioned at a "value node" which is not something that actually exists in an MMPT
|
||||||
func (s *Service) processStateValueNode(it trie.NodeIterator, headerID string, height *big.Int,
|
func (s *Service) processStateValueNode(it trie.NodeIterator, headerID string, height *big.Int, prefixPath []byte,
|
||||||
watchedAddressesLeafPaths [][]byte, tx Tx) error {
|
watchedAddressesLeafPaths [][]byte, tx Tx) error {
|
||||||
|
// create the full node path as it.Path() doesn't include the path before subtrie root
|
||||||
|
nodePath := append(prefixPath, it.Path()...)
|
||||||
// skip if it is not a watched address
|
// skip if it is not a watched address
|
||||||
// If we aren't watching any specific addresses, we are watching everything
|
// If we aren't watching any specific addresses, we are watching everything
|
||||||
if len(watchedAddressesLeafPaths) > 0 && !isWatchedAddress(watchedAddressesLeafPaths, it.Path()) {
|
if len(watchedAddressesLeafPaths) > 0 && !isWatchedAddress(watchedAddressesLeafPaths, nodePath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,8 +431,24 @@ func (s *Service) processStateValueNode(it trie.NodeIterator, headerID string, h
|
|||||||
if err := rlp.DecodeBytes(accountRLP, &account); err != nil {
|
if err := rlp.DecodeBytes(accountRLP, &account); err != nil {
|
||||||
return fmt.Errorf("error decoding account for leaf value at leaf key %x\nerror: %v", it.LeafKey(), err)
|
return fmt.Errorf("error decoding account for leaf value at leaf key %x\nerror: %v", it.LeafKey(), err)
|
||||||
}
|
}
|
||||||
leafKey := make([]byte, len(it.LeafKey()))
|
|
||||||
copy(leafKey, it.LeafKey())
|
// since this is a "value node", we need to move up to the "parent" node which is the actual leaf node
|
||||||
|
// it should be in the fastcache since it necessarily was recently accessed to reach the current "node"
|
||||||
|
parentNodeRLP, err := s.stateDB.TrieDB().Node(it.Parent())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var nodeElements []interface{}
|
||||||
|
if err = rlp.DecodeBytes(parentNodeRLP, &nodeElements); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
parentSubPath := make([]byte, len(it.ParentPath()))
|
||||||
|
copy(parentSubPath, it.ParentPath())
|
||||||
|
parentPath := append(prefixPath, parentSubPath...)
|
||||||
|
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
|
||||||
|
valueNodePath := append(parentPath, partialPath...)
|
||||||
|
encodedPath := trie.HexToCompact(valueNodePath)
|
||||||
|
leafKey := encodedPath[1:]
|
||||||
|
|
||||||
// write codehash => code mappings if we have a contract
|
// write codehash => code mappings if we have a contract
|
||||||
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
|
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
|
||||||
@ -438,17 +457,11 @@ func (s *Service) processStateValueNode(it trie.NodeIterator, headerID string, h
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to retrieve code for codehash %s\r\n error: %v", codeHash.String(), err)
|
return fmt.Errorf("failed to retrieve code for codehash %s\r\n error: %v", codeHash.String(), err)
|
||||||
}
|
}
|
||||||
if _, err := s.ipfsPublisher.PublishIPLD(ipld.Keccak256ToCid(ipld.RawBinary, codeHash.Bytes()), code, height, tx); err != nil {
|
if err := s.ipfsPublisher.PublishIPLD(ipld.Keccak256ToCid(ipld.RawBinary, codeHash.Bytes()), code, height, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// since this is a "value node", we need to move up to the "parent" node which is the actual leaf node
|
|
||||||
// it should be in the fastcache since it necessarily was recently accessed to reach the current node
|
|
||||||
parentNodeRLP, err := s.stateDB.TrieDB().Node(it.Parent())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// publish the state leaf model
|
// publish the state leaf model
|
||||||
stateKeyStr := common.BytesToHash(leafKey).String()
|
stateKeyStr := common.BytesToHash(leafKey).String()
|
||||||
stateLeafNodeModel := &models.StateNodeModel{
|
stateLeafNodeModel := &models.StateNodeModel{
|
||||||
@ -495,7 +508,7 @@ func (s *Service) storageSnapshot(sr common.Hash, stateKey, headerID string, hei
|
|||||||
copy(nodeVal, it.NodeBlob())
|
copy(nodeVal, it.NodeBlob())
|
||||||
nodeHash := make([]byte, len(it.Hash().Bytes()))
|
nodeHash := make([]byte, len(it.Hash().Bytes()))
|
||||||
copy(nodeHash, it.Hash().Bytes())
|
copy(nodeHash, it.Hash().Bytes())
|
||||||
if _, err := s.ipfsPublisher.PublishIPLD(ipld.Keccak256ToCid(ipld.MEthStorageTrie, nodeHash), nodeVal, height, tx); err != nil {
|
if err := s.ipfsPublisher.PublishIPLD(ipld.Keccak256ToCid(ipld.MEthStorageTrie, nodeHash), nodeVal, height, tx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user