예제 #1
0
        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);
            }
        }
예제 #2
0
        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();
        }