JavaScript merkle-patricia-tree/secure – OutOfMemory beim Durchlaufen großer (~70 GB) Zustandsversuche

Ich habe den folgenden JavaScript-Code, der den State Trie von geths Leveldb für den Ethereum-Mainnet-Block #5200035 durchläuft.

Nach einiger Zeit mit hoher CPU-Auslastung und nachdem etwa 6 GB RAM reserviert wurden, stürzt es mit FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Es sieht so aus, als hätte die Bibliothek Probleme mit der Größe der Mainnet-Datenbank (~70 GB nach einer schnellen Synchronisierung). Eine einfache Schlüssel/Wert-Suche mit db.getfunktioniert gut. Wenn ich versuche, etwas Kleineres wie den Speicherversuch eines Vertrags (versucht mit 0xd0a6E6C54DbC68Db5db3A091B171A77407Ff7ccf) zu durchlaufen, funktioniert es auch gut.

Irgendeine Idee, wie man dieses Problem angeht?

var Trie = require('merkle-patricia-tree/secure');
var levelup = require('levelup');
var leveldown = require('leveldown');

//Connecting to the leveldb database
var db = levelup(leveldown('../datadir/geth/chaindata'));

//Adding the "stateRoot" value from the block so that we can inspect the state root at that block height.
var root = "0x4d675087a16f13fa5f61af74d79e08c82de7cf200e63d5b225b4a7937705a3e2"; // Block #5200035

//Creating a trie object of the merkle-patricia-tree library
var trie = new Trie(db, root);

//Creating a nodejs stream object so that we can access the data
var stream = trie.createReadStream()

//Turning on the stream (because the node js stream is set to pause by default)
stream.on('data', function (data){
  console.log(data)
});

Diese Frage bezieht sich auf Wie werden alle Vertragsinstanzen gesammelt und die Bytecode-Redundanzen gezählt?

Antworten (1)

Pull-Request für den Fix https://github.com/ethereumjs/merkle-patricia-tree/pull/38


Vorherige Antwort

Ich bin mir nicht 100% sicher, aber ich denke, das Problem liegt in der Verwendung von async.forEachOf() zum Durchlaufen der Kinder eines Knotens in baseTrie.jsder processNodeFunktion https://github.com/ethereumjs/merkle-patricia-tree/blob/ dc436426d717fed408f4d46fed23f6d26d03d39d/baseTrie.js#L447 :

 function processNode (nodeRef, node, key, cb) {
    if (!node) return cb()
    if (aborted) return cb()
    var stopped = false
    key = key || []

    var walkController = {
      stop: function () {
        stopped = true
        cb()
      },
      // end all traversal and return values to the onDone cb
      return: function () {
        aborted = true
        returnValues = arguments
        cb()
      },
      next: function () {
        if (aborted) {
          return cb()
        }
        if (stopped) {
          return cb()
        }
        var children = node.getChildren()
        async.forEachOf(children, function (childData, index, cb) {
          var keyExtension = childData[0]
          var childRef = childData[1]
          var childKey = key.concat(keyExtension)
          self._lookupNode(childRef, function (childNode) {
            processNode(childRef, childNode, childKey, cb)
          })
        }, cb)
      },
      only: function (childIndex) {
        var childRef = node.getValue(childIndex)
        self._lookupNode(childRef, function (childNode) {
          var childKey = key.slice()
          childKey.push(childIndex)
          processNode(childRef, childNode, childKey, cb)
        })
      }
    }
    onNode(nodeRef, node, key, walkController)
  }

Wenn Sie hier async verwenden, wird der Trie zuerst in der Breite durchlaufen, im Gegensatz zu zuerst in der Tiefe, wenn Sie synchrones Traversal verwenden (Breite zuerst bedeutet im Grunde, dass Sie den gesamten Trie mit den aktuellen ~ 30 Millionen Konten in den Speicher laden, bevor Sie den ersten Schlüssel im Stream erhalten im Zustand kann es leicht 6 GB überschreiten). Ich würde versuchen, es in eine einfache for-Schleife zu ändern und zu sehen, ob es das Problem behoben hat (leider kann ich es jetzt nicht testen, da ich die Mainnet-Kettendaten nicht habe).

Oder versuchen Sie vielleicht, eine andere Bibliothek zum Lesen des Patricia Merkle Trie zu verwenden.

Haben Sie Vorschläge für eine andere Trie-JavaScript-Bibliothek?
Andere Libs habe ich leider noch nicht ausprobiert. Melde mich wenn ich was gutes finde :)
Versuchen Sie diesen Fix github.com/medvedev1088/merkle-patricia-tree/pull/1/files . Ich erstelle einen Pool und eine Prioritätswarteschlange, sodass Knoten mit längeren Schlüsseln zuerst gesucht werden. OOM für mich behoben. Ich bin kein JavaScript-Experte, daher kann ich dort hässlichen Code finden. Alle Kommentare sind willkommen.
Funktioniert! Höchstwahrscheinlich untertreibe ich es, wenn ich sage, dass Sie ein Genie sind! Schade, dass ich den Upvote nicht mehrfach pushen kann. :-)
Vielen Dank :). Aber überprüfen Sie zuerst meinen Code. Es könnte dort Fehler geben, also verlassen Sie sich nicht blind darauf.