Skip to content
This repository has been archived by the owner on Jan 19, 2021. It is now read-only.

Trie.prototype._updateNode(); TypeError: Cannot read property 'pop' of undefined #12

Closed
Ryanmtate opened this issue May 3, 2016 · 4 comments

Comments

@Ryanmtate
Copy link

Ryanmtate commented May 3, 2016

_updateNode is receiving undefined stack

Receiving TypeError: Cannot read property 'pop' of undefined

patricia-tree/baseTrie.js:359
  var lastNode = stack.pop()

                      ^

TypeError: Cannot read property 'pop' of undefined

Suspect WalkController is not passing stack in the callback of processNode();

Trie.prototype._findPath = function (targetKey, cb) {
  var self = this
  var root = self.root
  var stack = []
  targetKey = TrieNode.stringToNibbles(targetKey)

  this._walkTrie(root, processNode, cb)

  function processNode (root, node, keyProgress, walkController) {
    var nodeKey = node.key || []
    var keyRemainder = targetKey.slice(matchingNibbleLength(keyProgress, targetKey))
    var matchingLen = matchingNibbleLength(keyRemainder, nodeKey)

    stack.push(node)

    if (node.type === 'branch') {
      if (keyRemainder.length === 0) {
        walkController.return(null, node, [], stack)
      // we exhausted the key without finding a node
      } else {
        var branchIndex = keyRemainder[0]
        var branchNode = node.getValue(branchIndex)
        if (!branchNode) {
          // there are no more nodes to find and we didn't find the key
          walkController.return(null, null, keyRemainder, stack)
        } else {
          // node found, continuing search
          walkController.only(branchIndex)
        }
      }
    } else if (node.type === 'leaf') {
      if (doKeysMatch(keyRemainder, nodeKey)) {
        // keys match, return node with empty key
        walkController.return(null, node, [], stack)
      } else {
        // reached leaf but keys dont match
        walkController.return(null, null, keyRemainder, stack)
      }
    } else if (node.type === 'extention') {
      if (matchingLen !== nodeKey.length) {
        // keys dont match, fail
        walkController.return(null, null, keyRemainder, stack)
      } else {
        // keys match, continue search
        walkController.next()
      }
    }
  }
}
@wanderer
Copy link
Member

wanderer commented May 6, 2016

@Ryanmtate do you have the code that generates this error?

@tcoulter
Copy link

tcoulter commented Mar 7, 2017

I've seen this a bunch with the TestRPC. Was too intermittent to figure out the root cause however.

@erkmos
Copy link

erkmos commented Apr 22, 2017

This problem still exists with TestRPC, I've spent a few hours trying to track down how to fix it, but so far haven't figured out how. Callback hell...

I've tried making it pass an error in the callback from watchController.only in walkTrie helper processNode but there seems to be a lot of code elsewhere that doesn't follow the callback(error, value) convention, causing all kinds of strange behaviour. I squashed many of those, but I don't think calling the continuation in only with an error if node is undefined is the right fix. It seems to put the server's state manager in a broken state, all subsequent calls return the same error. Don't fully understand all the surrounding code yet.

Giving up for now, might look at it again later if I have time. But I'm documenting my findings below if anyone else has the patience:

The symptoms start with this line in Trie._findPath's processNode

walkController.only(branchIndex)

which then runs this function

only: function (childIndex) {
    var childRoot = node.getValue(childIndex)
    self._lookupNode(childRoot, function (node) { // node is undefined here
        var childKey = key.slice()
        childKey.push(childIndex)
        processNode(childRoot, node, childKey, cb)
    })
}

In the recursive call for processNode from above it calls this line

if (!node) return cb() <-- no arguments

this is cb from above

if (err) {
  return onDone(err)
}
// returnValues is an empty array from the walkTrie closure, so essentially onDone()
onDone.apply(null, returnValues) 

onDone from above is the callback in Trie.put at this line

self._findPath(key, function (err, foundValue, keyRemainder, stack) {
    // all arguments here are undefined because it gets called with no arguments
    if (err) {
        return cb(err);
    }
    // then update
    // this call crashes the program because stack is undefined
    self._updateNode(key, value, keyRemainder, stack, cb)
})

@holgerd77
Copy link
Member

Will cautiously close this since the issue is pretty old, there hasn't been any reports lately and the code base changed significantly since. There has also been a refactor of the WalkController in #135 by @jochem-brouwer. Feel free to reopen though if you still think this is an issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants