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 <StorageAddress, ChangeTrace> trace = null; if (isTracing) { trace = new Dictionary <StorageAddress, ChangeTrace>(); } for (int i = 0; i <= _currentPosition; i++) { Change change = _changes[_currentPosition - i]; if (_committedThisRound.Contains(change.StorageAddress)) { if (isTracing && change.ChangeType == ChangeType.JustCache) { trace[change.StorageAddress] = new ChangeTrace(change.Value, trace[change.StorageAddress].After); } continue; } // if (_destructedStorages.ContainsKey(change.StorageAddress.Address)) // { // if (_destructedStorages[change.StorageAddress.Address].ChangeIndex > _currentPosition - i) // { // continue; // } // } _committedThisRound.Add(change.StorageAddress); if (change.ChangeType == ChangeType.Destroy) { continue; } int forAssertion = _intraBlockCache[change.StorageAddress].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.StorageAddress.Address}_{change.StorageAddress.Index} V = {change.Value.ToHexString(true)}"); } StorageTree tree = GetOrCreateStorage(change.StorageAddress.Address); Metrics.StorageTreeWrites++; toUpdateRoots.Add(change.StorageAddress.Address); tree.Set(change.StorageAddress.Index, change.Value); if (isTracing) { trace[change.StorageAddress] = 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); } } _capacity = Math.Max(StartCapacity, _capacity / 2); _changes = new Change[_capacity]; _currentPosition = -1; _committedThisRound = new HashSet <StorageAddress>(Math.Max(StartCapacity, _committedThisRound.Count / 2)); _intraBlockCache = new Dictionary <StorageAddress, Stack <int> >(Math.Max(StartCapacity, _intraBlockCache.Count / 2)); _originalValues = new Dictionary <StorageAddress, byte[]>(Math.Max(StartCapacity, _originalValues.Count / 2)); // _destructedStorages.Clear(); if (isTracing) { ReportChanges(tracer, trace); } }
public void Commit(IReleaseSpec spec) { 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>(); for (int i = 0; i <= _currentPosition; i++) { Change change = _changes[_currentPosition - i]; if (_committedThisRound.Contains(change.StorageAddress)) { continue; } int forAssertion = _cache[change.StorageAddress].Pop(); if (forAssertion != _currentPosition - i) { throw new InvalidOperationException($"Expected checked value {forAssertion} to be equal to {_currentPosition} - {i}"); } _committedThisRound.Add(change.StorageAddress); toUpdateRoots.Add(change.StorageAddress.Address); switch (change.ChangeType) { case ChangeType.JustCache: break; case ChangeType.Update: if (_logger.IsTrace) { _logger.Trace($" UPDATE {change.StorageAddress.Address}_{change.StorageAddress.Index} V = {change.Value.ToHexString(true)}"); } StorageTree tree = GetOrCreateStorage(change.StorageAddress.Address); Metrics.StorageTreeWrites++; tree.Set(change.StorageAddress.Index, change.Value); //_storageCache.Set(change.StorageAddress, change.Value); break; default: throw new ArgumentOutOfRangeException(); } } foreach (Address address in toUpdateRoots) { // TODO: this is tricky... for EIP-158 if (_stateProvider.AccountExists(address)) { Keccak root = GetRoot(address); _stateProvider.UpdateStorageRoot(address, root); } } _capacity = Math.Max(StartCapacity, _capacity / 2); _changes = new Change[_capacity]; _currentPosition = -1; _committedThisRound.Clear(); _cache.Clear(); }