public StateReader(ITrieStore?trieStore, IDb?codeDb, ILogManager?logManager) { _logger = logManager?.GetClassLogger <StateReader>() ?? throw new ArgumentNullException(nameof(logManager)); _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); _state = new StateTree(trieStore, logManager); _storage = new StorageTree(trieStore, Keccak.EmptyTreeHash, logManager); }
private Keccak RecalculateRootHash(Address address) { StorageTree storageTree = GetOrCreateStorage(address); storageTree.UpdateRootHash(); return(storageTree.RootHash); }
private byte[] LoadFromTree(StorageCell storageCell) { StorageTree tree = GetOrCreateStorage(storageCell.Address); Metrics.StorageTreeReads++; byte[] value = tree.Get(storageCell.Index); PushToRegistryOnly(storageCell, value); return(value); }
private StorageTree GetOrCreateStorage(Address address) { if (!_storages.ContainsKey(address)) { StorageTree storageTree = new StorageTree(_stateDb, _stateProvider.GetStorageRoot(address)); return(_storages[address] = storageTree); } return(_storages[address]); }
public StateReader(ISnapshotableDb stateDb, IDb codeDb, ILogManager logManager) { if (stateDb == null) { throw new ArgumentNullException(nameof(stateDb)); } _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); _state = new StateTree(stateDb); _storage = new StorageTree(stateDb); }
public void ClearStorage(Address address) { /* we are setting cached values to zero so we do not use previously set values * when the contract is revived with CREATE2 inside the same block */ foreach (var cellByAddress in _intraBlockCache) { if (cellByAddress.Key.Address == address) { Set(cellByAddress.Key, _zeroValue); } } /* here it is important to make sure that we will not reuse the same tree when the contract is revived * by means of CREATE 2 - notice that the cached trie may carry information about items that were not * touched in this block, hence were not zeroed above */ _storages[address] = new StorageTree(_stateDb, Keccak.EmptyTreeHash); }
public void Commit(IStorageTracer tracer) { if (_currentPosition == -1) { if (_logger.IsTrace) { _logger.Trace("No storage changes to commit"); } return; } if (_logger.IsTrace) { _logger.Trace("Committing storage changes"); } if (_changes[_currentPosition] == null) { throw new InvalidOperationException($"Change at current position {_currentPosition} was null when commiting {nameof(StorageProvider)}"); } if (_changes[_currentPosition + 1] != null) { throw new InvalidOperationException($"Change after current position ({_currentPosition} + 1) was not null when commiting {nameof(StorageProvider)}"); } HashSet <Address> toUpdateRoots = new HashSet <Address>(); bool isTracing = tracer != null; Dictionary <StorageCell, ChangeTrace> trace = null; if (isTracing) { trace = new Dictionary <StorageCell, ChangeTrace>(); } for (int i = 0; i <= _currentPosition; i++) { Change change = _changes[_currentPosition - i]; if (!isTracing && change.ChangeType == ChangeType.JustCache) { continue; } if (_committedThisRound.Contains(change.StorageCell)) { if (isTracing && change.ChangeType == ChangeType.JustCache) { trace[change.StorageCell] = new ChangeTrace(change.Value, trace[change.StorageCell].After); } continue; } if (isTracing && change.ChangeType == ChangeType.JustCache) { tracer.ReportStorageRead(change.StorageCell); } _committedThisRound.Add(change.StorageCell); if (change.ChangeType == ChangeType.Destroy) { continue; } int forAssertion = _intraBlockCache[change.StorageCell].Pop(); if (forAssertion != _currentPosition - i) { throw new InvalidOperationException($"Expected checked value {forAssertion} to be equal to {_currentPosition} - {i}"); } switch (change.ChangeType) { case ChangeType.Destroy: break; case ChangeType.JustCache: break; case ChangeType.Update: if (_logger.IsTrace) { _logger.Trace($" Update {change.StorageCell.Address}_{change.StorageCell.Index} V = {change.Value.ToHexString(true)}"); } StorageTree tree = GetOrCreateStorage(change.StorageCell.Address); Metrics.StorageTreeWrites++; toUpdateRoots.Add(change.StorageCell.Address); tree.Set(change.StorageCell.Index, change.Value); if (isTracing) { trace[change.StorageCell] = new ChangeTrace(change.Value); } break; default: throw new ArgumentOutOfRangeException(); } } foreach (Address address in toUpdateRoots) { // since the accounts could be empty accounts that are removing (EIP-158) if (_stateProvider.AccountExists(address)) { Keccak root = RecalculateRootHash(address); _stateProvider.UpdateStorageRoot(address, root); } } Resettable <Change> .Reset(ref _changes, ref _capacity, ref _currentPosition, StartCapacity); _committedThisRound.Reset(); _intraBlockCache.Reset(); _originalValues.Reset(); if (isTracing) { ReportChanges(tracer, trace); } }