Loading...
Loading...
// Упрощенный алгоритм вычисления Storage Rootfunction calculateStorageRoot(storage) { // 1. Создаем пустое дерево const trie = new MerklePatriciaTrie();
// 2. Добавляем каждую пару ключ-значение for (const [key, value] of Object.entries(storage)) { const hashedKey = keccak256(key); const encodedValue = rlp.encode(value); trie.put(hashedKey, encodedValue); }
// 3. Возвращаем корневой хеш return trie.root;}
Слова: CAT, CAR, CARD, CARE, CAREFUL
ROOT | C | A / \ T R |\ | D | E | F-U-L
State Root | Node / \Node Node | |Leaf Branch(Account) | Leaf (Account)
// Содержит конечные данные{ type: "leaf", key: "0x742d35Cc...", // Остаток ключа value: { // Данные аккаунта balance: "1500000000000000000", nonce: 42, codeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", storageRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" }}
// Сжимает общие префиксы{ type: "extension", key: "0x742d35", // Общий префикс value: "0x1234..." // Хеш следующего узла}
// Имеет до 16 детей (0-F в hex){ type: "branch", children: [ "0x1234...", // Ребенок для '0' "0x5678...", // Ребенок для '1' null, // Нет ребенка для '2' // ... до 'F' null // Значение для этого узла (если есть) ]}
// Поиск аккаунта по адресуasync function getAccount(address) { // 1. Хешируем адрес для получения ключа const key = keccak256(address); console.log(`Ключ: ${key}`);
// 2. Начинаем с корня State Trie let currentNode = await getNode(stateRoot); let keyIndex = 0;
while (keyIndex < key.length) { if (currentNode.type === 'leaf') { // Нашли листовой узел if (key.slice(keyIndex) === currentNode.key) { return currentNode.value; // Данные аккаунта } else { return null; // Аккаунт не найден } } else if (currentNode.type === 'extension') { // Проверяем совпадение префикса if ( key.slice(keyIndex, keyIndex + currentNode.key.length) === currentNode.key ) { keyIndex += currentNode.key.length; currentNode = await getNode(currentNode.value); } else { return null; // Путь не совпадает } } else if (currentNode.type === 'branch') { // Переходим к соответствующему ребенку const nibble = key[keyIndex]; if (currentNode.children[nibble]) { currentNode = await getNode(currentNode.children[nibble]); keyIndex++; } else { return null; // Путь не существует } } }
return null;}
Типы ключей в Ethereum:
'h' + номер + хеш → заголовок блока'b' + номер + хеш → тело блока'r' + номер + хеш → квитанции блока'l' + хеш → номер блока (lookup)'secure-key-' + хеш → данные State Trie
// Примеры записей в LevelDBconst dbRecords = { // Заголовок блока 'h18500000-0x1234abcd...': { number: 18500000, timestamp: 1699123456, parentHash: '0x5678efgh...', stateRoot: '0x9abc1234...' },
// Узел State Trie 'secure-key-0x9abc1234...': { type: 'branch', children: ['0x1111...', '0x2222...', null, ...] },
// Данные аккаунта 'secure-key-0x3333cccc...': { balance: '1500000000000000000', nonce: 42, codeHash: '0x4444dddd...', storageRoot: '0x5555eeee...' }};
// RLP (Recursive Length Prefix) кодированиеconst account = { nonce: 42, balance: '1500000000000000000', storageRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470',};
// RLP кодирование сжимает данныеconst encoded = rlp.encode([ account.nonce, account.balance, account.storageRoot, account.codeHash,]);
Пустые аккаунты имеют одинаковый storageRoot:0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
Этот хеш хранится только один раз в базе!
Snapshot содержит:- Плоский список всех аккаунтов- Быстрый доступ без обхода Trie- Периодическое обновление- Используется для синхронизации
// Подключение к ноде Gethgeth attach
// Получение информации об аккаунте> eth.getBalance("0x742d35Cc6634C0532925a3b8D4C9db96590c6C87")1500000000000000000
// Получение nonce> eth.getTransactionCount("0x742d35Cc6634C0532925a3b8D4C9db96590c6C87")42
// Получение кода контракта> eth.getCode("0x742d35Cc6634C0532925a3b8D4C9db96590c6C87")"0x608060405234801561001057600080fd5b50..."
const Web3 = require('web3');const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');
// Анализ состояния аккаунтаasync function analyzeAccount(address) { console.log(`=== Анализ аккаунта ${address} ===`);
// Баланс const balance = await web3.eth.getBalance(address); console.log(`Баланс: ${web3.utils.fromWei(balance, 'ether')} ETH`);
// Nonce const nonce = await web3.eth.getTransactionCount(address); console.log(`Nonce: ${nonce}`);
// Код (если это контракт) const code = await web3.eth.getCode(address); if (code !== '0x') { console.log(`Это смарт-контракт!`); console.log(`Размер кода: ${(code.length - 2) / 2} байт`); } else { console.log(`Это обычный аккаунт (EOA)`); }
// Хранилище контракта (если есть) if (code !== '0x') { const storage0 = await web3.eth.getStorageAt(address, 0); console.log(`Storage slot 0: ${storage0}`); }}
// Пример использованияanalyzeAccount('0x742d35Cc6634C0532925a3b8D4C9db96590c6C87');
// Получение State Root текущего блокаasync function getCurrentStateRoot() { const latestBlock = await web3.eth.getBlock('latest'); console.log(`State Root: ${latestBlock.stateRoot}`); return latestBlock.stateRoot;}
// Проверка существования аккаунтаasync function accountExists(address) { const balance = await web3.eth.getBalance(address); const nonce = await web3.eth.getTransactionCount(address); const code = await web3.eth.getCode(address);
const exists = balance !== '0' || nonce > 0 || code !== '0x'; console.log(`Аккаунт ${address} ${exists ? 'существует' : 'не существует'}`); return exists;}
Полная нода Ethereum (2024):├── Chaindata: ~800 GB│ ├── State Database: ~200 GB│ ├── Block Database: ~400 GB│ ├── Transaction Database: ~150 GB│ └── Receipt Database: ~50 GB├── Ancient Data: ~300 GB└── Snapshots: ~100 GB
Итого: ~1.2 TB
Аккаунтов в State: ~100 миллионовБлоков: ~18.5 миллионовТранзакций: ~2 миллиардаКонтрактов: ~50 миллионов
// Создание снапшота состоянияclass StateSnapshot { constructor() { this.accounts = new Map(); this.blockNumber = 0; }
// Создание снапшота async createSnapshot(blockNumber) { console.log(`Создание снапшота для блока ${blockNumber}...`);
const block = await web3.eth.getBlock(blockNumber); this.blockNumber = blockNumber;
// Обход всех аккаунтов (упрощенно) for (const address of this.getAllAddresses()) { const account = { balance: await web3.eth.getBalance(address, blockNumber), nonce: await web3.eth.getTransactionCount(address, blockNumber), code: await web3.eth.getCode(address, blockNumber), }; this.accounts.set(address, account); }
console.log(`Снапшот создан: ${this.accounts.size} аккаунтов`); }
// Быстрый доступ к данным getAccount(address) { return this.accounts.get(address); }}
Типы pruning:- Archive: хранит все (1+ TB)- Full: хранит последние 128 блоков (~800 GB)- Light: хранит только заголовки (~1 GB)
Режимы синхронизации:- Full: загружает все блоки с генезиса- Fast: загружает состояние + последние блоки- Snap: загружает снапшот + последние блоки- Light: загружает только заголовки
Ethereum 2.0 Sharding:- 64 шарда- Каждый шард хранит часть состояния- Beacon Chain координирует шарды- Значительное увеличение пропускной способности
Концепция Stateless:- Ноды не хранят полное состояние- Состояние передается с транзакциями- Witness data доказывает корректность- Значительное уменьшение требований к хранению
// Проверка целостности данныхfunction verifyDataIntegrity(data, expectedHash) { const actualHash = keccak256(data); if (actualHash !== expectedHash) { throw new Error('Данные повреждены!'); } return true;}
// Проверка State Rootfunction verifyStateRoot(accounts, expectedRoot) { const calculatedRoot = buildMerklePatriciaTrie(accounts); if (calculatedRoot !== expectedRoot) { throw new Error('State Root не совпадает!'); } return true;}
# Создание бэкапа Gethgeth export blockchain.rlp
# Бэкап базы данныхcp -r ~/.ethereum/geth/chaindata ./backup/
# Восстановление из бэкапаgeth import blockchain.rlp
// Мониторинг состояния базы данныхclass DatabaseMonitor { async checkHealth() { const checks = { connectivity: await this.checkConnectivity(), stateRoot: await this.verifyStateRoot(), diskSpace: await this.checkDiskSpace(), syncStatus: await this.checkSyncStatus(), };
console.log('Состояние базы данных:', checks); return checks; }
async checkConnectivity() { try { await web3.eth.getBlockNumber(); return 'OK'; } catch (error) { return 'ERROR: ' + error.message; } }
async verifyStateRoot() { const block = await web3.eth.getBlock('latest'); // Проверка State Root return 'OK'; }}