예제 #1
0
 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);
 }
예제 #2
0
        private Keccak RecalculateRootHash(Address address)
        {
            StorageTree storageTree = GetOrCreateStorage(address);

            storageTree.UpdateRootHash();
            return(storageTree.RootHash);
        }
예제 #3
0
        private byte[] LoadFromTree(StorageCell storageCell)
        {
            StorageTree tree = GetOrCreateStorage(storageCell.Address);

            Metrics.StorageTreeReads++;
            byte[] value = tree.Get(storageCell.Index);
            PushToRegistryOnly(storageCell, value);
            return(value);
        }
예제 #4
0
        private StorageTree GetOrCreateStorage(Address address)
        {
            if (!_storages.ContainsKey(address))
            {
                StorageTree storageTree = new StorageTree(_stateDb, _stateProvider.GetStorageRoot(address));
                return(_storages[address] = storageTree);
            }

            return(_storages[address]);
        }
예제 #5
0
 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);
 }
예제 #6
0
        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);
        }
예제 #7
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 <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);
            }
        }