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.get
funktioniert 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?
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.js
der processNode
Funktion 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.
ivicaa
medwedew1088
medwedew1088
ivicaa
medwedew1088