Beispiel #1
0
        private void InitializeTestState(BlockchainTest test, IStateProvider stateProvider, IStorageProvider storageProvider, ISpecProvider specProvider)
        {
            foreach (KeyValuePair <Address, AccountState> accountState in
                     ((IEnumerable <KeyValuePair <Address, AccountState> >)test.Pre ?? Array.Empty <KeyValuePair <Address, AccountState> >()))
            {
                foreach (KeyValuePair <UInt256, byte[]> storageItem in accountState.Value.Storage)
                {
                    storageProvider.Set(new StorageCell(accountState.Key, storageItem.Key), storageItem.Value);
                }

                stateProvider.CreateAccount(accountState.Key, accountState.Value.Balance);
                Keccak codeHash = stateProvider.UpdateCode(accountState.Value.Code);
                stateProvider.UpdateCodeHash(accountState.Key, codeHash, specProvider.GenesisSpec);
                for (int i = 0; i < accountState.Value.Nonce; i++)
                {
                    stateProvider.IncrementNonce(accountState.Key);
                }
            }

            storageProvider.Commit();
            stateProvider.Commit(specProvider.GenesisSpec);

            storageProvider.CommitTrees(0);
            stateProvider.CommitTree(0);

            storageProvider.Reset();
            stateProvider.Reset();
        }
Beispiel #2
0
        private void InitializeTestState(GeneralStateTest test, IStateProvider stateProvider, IStorageProvider storageProvider, ISpecProvider specProvider)
        {
            foreach (KeyValuePair <Address, AccountState> accountState in test.Pre)
            {
                foreach (KeyValuePair <UInt256, byte[]> storageItem in accountState.Value.Storage)
                {
                    storageProvider.Set(new StorageCell(accountState.Key, storageItem.Key), storageItem.Value.WithoutLeadingZeros().ToArray());
                }

                stateProvider.CreateAccount(accountState.Key, accountState.Value.Balance);
                Keccak codeHash = stateProvider.UpdateCode(accountState.Value.Code);
                stateProvider.UpdateCodeHash(accountState.Key, codeHash, specProvider.GenesisSpec);
                for (int i = 0; i < accountState.Value.Nonce; i++)
                {
                    stateProvider.IncrementNonce(accountState.Key);
                }
            }

            storageProvider.Commit();
            stateProvider.Commit(specProvider.GenesisSpec);

            storageProvider.CommitTrees();
            stateProvider.CommitTree();

            storageProvider.Reset();
            stateProvider.Reset();
        }
        public Block[] Process(Keccak branchStateRoot, Block[] suggestedBlocks, ProcessingOptions options, IBlockTracer blockTracer)
        {
            if (_logger.IsTrace)
            {
                _logger.Trace($"Processing block {suggestedBlocks[0].Number} from state root: {branchStateRoot}");
            }

            if (suggestedBlocks.Length == 0)
            {
                return(Array.Empty <Block>());
            }

            int    stateSnapshot     = _stateDb.TakeSnapshot();
            int    codeSnapshot      = _codeDb.TakeSnapshot();
            Keccak snapshotStateRoot = _stateProvider.StateRoot;

            if (branchStateRoot != null && _stateProvider.StateRoot != branchStateRoot)
            {
                /* discarding the other branch data - chain reorganization */
                Metrics.Reorganizations++;
                _storageProvider.Reset();
                _stateProvider.Reset();
                _stateProvider.StateRoot = branchStateRoot;
            }

            var processedBlocks = new Block[suggestedBlocks.Length];

            try
            {
                for (int i = 0; i < suggestedBlocks.Length; i++)
                {
                    processedBlocks[i] = ProcessOne(suggestedBlocks[i], options, blockTracer);
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Committing trees - state root {_stateProvider.StateRoot}");
                    }
                    _stateProvider.CommitTree();
                    _storageProvider.CommitTrees();
                }

                if ((options & ProcessingOptions.ReadOnlyChain) != 0)
                {
                    Restore(stateSnapshot, codeSnapshot, snapshotStateRoot);
                }
                else
                {
                    _stateDb.Commit();
                    _codeDb.Commit();
                }

                return(processedBlocks);
            }
            catch (InvalidBlockException)
            {
                Restore(stateSnapshot, codeSnapshot, snapshotStateRoot);
                throw;
            }
        }
Beispiel #4
0
        public Block Load()
        {
            Block genesis = _chainSpec.Genesis;

            foreach ((Address address, ChainSpecAllocation allocation) in _chainSpec.Allocations.OrderBy(a => a.Key))
            {
                _stateProvider.CreateAccount(address, allocation.Balance);

                if (allocation.Code != null)
                {
                    Keccak codeHash = _stateProvider.UpdateCode(allocation.Code);
                    _stateProvider.UpdateCodeHash(address, codeHash, _specProvider.GenesisSpec);
                }

                if (allocation.Storage != null)
                {
                    foreach (KeyValuePair <UInt256, byte[]> storage in allocation.Storage)
                    {
                        _storageProvider.Set(new StorageCell(address, storage.Key), storage.Value.WithoutLeadingZeros().ToArray());
                    }
                }

                if (allocation.Constructor != null)
                {
                    Transaction constructorTransaction = new SystemTransaction()
                    {
                        SenderAddress = address,
                        Init          = allocation.Constructor,
                        GasLimit      = genesis.GasLimit
                    };

                    CallOutputTracer outputTracer = new CallOutputTracer();
                    _transactionProcessor.Execute(constructorTransaction, genesis.Header, outputTracer);

                    if (outputTracer.StatusCode != StatusCode.Success)
                    {
                        throw new InvalidOperationException($"Failed to initialize constructor for address {address}. Error: {outputTracer.Error}");
                    }
                }
            }

            // we no longer need the allocations - 0.5MB RAM, 9000 objects for mainnet
            _chainSpec.Allocations = null;

            _storageProvider.Commit();
            _stateProvider.Commit(_specProvider.GenesisSpec);

            _storageProvider.CommitTrees();
            _stateProvider.CommitTree();

            _dbProvider.StateDb.Commit();
            _dbProvider.CodeDb.Commit();

            genesis.Header.StateRoot = _stateProvider.StateRoot;
            genesis.Header.Hash      = genesis.Header.CalculateHash();

            return(genesis);
        }
Beispiel #5
0
 private void PreCommitBlock(Keccak newBranchStateRoot)
 {
     if (_logger.IsTrace)
     {
         _logger.Trace($"Committing the branch - {newBranchStateRoot} | {_stateProvider.StateRoot}");
     }
     _stateProvider.CommitTree();
     _storageProvider.CommitTrees();
 }
        public void Get_storage()
        {
            /* all testing will be touching just a single storage cell */
            var storageCell = new StorageCell(TestItem.AddressA, 1);

            /* to start with we need to create an account that we will be setting storage at */
            _stateProvider.CreateAccount(storageCell.Address, UInt256.One);
            _stateProvider.Commit(MuirGlacier.Instance);
            _stateProvider.CommitTree();

            /* at this stage we have an account with empty storage at the address that we want to test */

            byte[] initialValue = new byte[] { 1, 2, 3 };
            _storageProvider.Set(storageCell, initialValue);
            _storageProvider.Commit();
            _storageProvider.CommitTrees();
            _stateProvider.Commit(MuirGlacier.Instance);
            _stateProvider.CommitTree();

            var retrieved =
                _blockchainBridge.GetStorage(storageCell.Address, storageCell.Index, _stateProvider.StateRoot);

            retrieved.Should().BeEquivalentTo(initialValue);

            /* at this stage we set the value in storage to 1,2,3 at the tested storage cell */

            /* Now we are testing scenario where the storage is being changed by the block processor.
            *  To do that we create some different storage / state access stack that represents the processor.
            *  It is a different stack of objects than the one that is used by the blockchain bridge. */

            byte[] newValue = new byte[] { 1, 2, 3, 4, 5 };

            StateProvider processorStateProvider =
                new StateProvider(_dbProvider.StateDb, _dbProvider.CodeDb, LimboLogs.Instance);

            processorStateProvider.StateRoot = _stateProvider.StateRoot;

            StorageProvider processorStorageProvider =
                new StorageProvider(_dbProvider.StateDb, processorStateProvider, LimboLogs.Instance);

            processorStorageProvider.Set(storageCell, newValue);
            processorStorageProvider.Commit();
            processorStorageProvider.CommitTrees();
            processorStateProvider.Commit(MuirGlacier.Instance);
            processorStateProvider.CommitTree();

            /* At this stage the DB should have the storage value updated to 5.
             * We will try to retrieve the value by taking the state root from the processor.*/

            retrieved =
                _blockchainBridge.GetStorage(storageCell.Address, storageCell.Index, processorStateProvider.StateRoot);
            retrieved.Should().BeEquivalentTo(newValue);

            /* If it failed then it means that the blockchain bridge cached the previous call value */
        }
Beispiel #7
0
        private Block ProcessOne(Block suggestedBlock, bool tryOnly)
        {
            Block processedBlock = suggestedBlock;

            if (!suggestedBlock.IsGenesis)
            {
                processedBlock = ProcessNonGenesis(suggestedBlock, tryOnly);
            }

            _stateProvider.CommitTree();
            _storageProvider.CommitTrees();

            return(processedBlock);
        }
Beispiel #8
0
        private Block ProcessOne(Block suggestedBlock, bool tryOnly)
        {
            IDb   db             = _dbProvider.GetOrCreateStateDb();
            Block processedBlock = suggestedBlock;

            if (!suggestedBlock.IsGenesis)
            {
                processedBlock = ProcessNonGenesis(suggestedBlock, tryOnly);
            }

            db.StartBatch();
            _stateProvider.CommitTree();
            _storageProvider.CommitTrees();
            db.CommitBatch();

            _dbProvider.Commit(_specProvider.GetSpec(suggestedBlock.Number));
            return(processedBlock);
        }
Beispiel #9
0
        public Block Load()
        {
            Block genesis = _chainSpec.Genesis;

            foreach ((Address address, ChainSpecAllocation allocation) in _chainSpec.Allocations)
            {
                _stateProvider.CreateAccount(address, allocation.Balance);
                if (allocation.Code != null)
                {
                    Keccak codeHash = _stateProvider.UpdateCode(allocation.Code);
                    _stateProvider.UpdateCodeHash(address, codeHash, _specProvider.GenesisSpec);
                }

                if (allocation.Constructor != null)
                {
                    Transaction constructorTransaction = new SystemTransaction()
                    {
                        SenderAddress = address,
                        Init          = allocation.Constructor,
                        GasLimit      = genesis.GasLimit
                    };

                    _transactionProcessor.Execute(constructorTransaction, genesis.Header, NullTxTracer.Instance);
                }
            }

            // we no longer need the allocations - 0.5MB RAM, 9000 objects for mainnet
            _chainSpec.Allocations = null;

            _storageProvider.Commit();
            _stateProvider.Commit(_specProvider.GenesisSpec);

            _storageProvider.CommitTrees();
            _stateProvider.CommitTree();

            _dbProvider.StateDb.Commit();
            _dbProvider.CodeDb.Commit();

            genesis.Header.StateRoot = _stateProvider.StateRoot;
            genesis.Header.Hash      = genesis.Header.CalculateHash();

            return(genesis);
        }
Beispiel #10
0
        public Block Load()
        {
            Block genesis = _chainSpec.Genesis;

            Preallocate(genesis);

            // we no longer need the allocations - 0.5MB RAM, 9000 objects for mainnet
            _chainSpec.Allocations = null;

            _storageProvider.Commit();
            _stateProvider.Commit(_specProvider.GenesisSpec);

            _storageProvider.CommitTrees(0);
            _stateProvider.CommitTree(0);

            genesis.Header.StateRoot = _stateProvider.StateRoot;
            genesis.Header.Hash      = genesis.Header.CalculateHash();

            return(genesis);
        }
Beispiel #11
0
        public DeltaCache(IHashProvider hashProvider,
                          IMemoryCache memoryCache,
                          IDeltaDfsReader dfsReader,
                          IDeltaCacheChangeTokenProvider changeTokenProvider,
                          IStorageProvider storageProvider,
                          IStateProvider stateProvider,
                          ISnapshotableDb stateDb,
                          IDeltaIndexService deltaIndexService,
                          ILogger logger)
        {
            _deltaIndexService = deltaIndexService;

            stateProvider.CreateAccount(TruffleTestAccount, 1_000_000_000.Kat());
            stateProvider.CreateAccount(CatalystTruffleTestAccount, 1_000_000_000.Kat());

            storageProvider.Commit();
            stateProvider.Commit(CatalystGenesisSpec.Instance);

            storageProvider.CommitTrees();
            stateProvider.CommitTree();

            stateDb.Commit();

            var genesisDelta = new Delta
            {
                TimeStamp = Timestamp.FromDateTime(DateTime.UnixEpoch),
                StateRoot = ByteString.CopyFrom(stateProvider.StateRoot.Bytes),
            };


            GenesisHash = hashProvider.ComputeMultiHash(genesisDelta).ToCid();

            _dfsReader    = dfsReader;
            _logger       = logger;
            _entryOptions = () => new MemoryCacheEntryOptions()
                            .AddExpirationToken(changeTokenProvider.GetChangeToken())
                            .RegisterPostEvictionCallback(EvictionCallback);

            _memoryCache = memoryCache;
            _memoryCache.Set(GenesisHash, genesisDelta);
        }
Beispiel #12
0
        private void Execute(Delta delta, ITxTracer txTracer, bool readOnly)
        {
            var stateUpdate = ToStateUpdate(delta);

            // revert state if any fails (take snapshot)
            foreach (var publicEntry in delta.PublicEntries)
            {
                Execute(publicEntry, stateUpdate, txTracer);
            }

            var spec = _specProvider.GetSpec(stateUpdate.Number);

            _storageProvider.Commit(txTracer.IsTracingState ? txTracer : null);
            _stateProvider.Commit(spec, txTracer.IsTracingState ? txTracer : null);

            _stateProvider.RecalculateStateRoot();
            if (!readOnly)
            {
                if (new Keccak(delta.StateRoot.ToByteArray()) != _stateProvider.StateRoot)
                {
                    if (_logger.IsEnabled(LogEventLevel.Error))
                    {
                        _logger.Error("Invalid delta state root - found {found} and should be {shouldBe}", _stateProvider.StateRoot, new Keccak(delta.StateRoot.ToByteArray()));
                    }
                }

                // compare state roots
                _storageProvider.CommitTrees();
                _stateProvider.CommitTree();
            }
            else
            {
                delta.StateRoot = _stateProvider.StateRoot.ToByteString();
                if (_logger.IsEnabled(LogEventLevel.Debug))
                {
                    _logger.Debug($"Setting candidate delta {delta.DeltaNumber} root to {delta.StateRoot.ToKeccak()}");
                }
                _stateProvider.Reset();
                _storageProvider.Reset();
            }
        }
Beispiel #13
0
        private void Execute(Delta delta, ITxTracer txTracer, bool readOnly)
        {
            var stateUpdate = ToStateUpdate(delta);

            // revert state if any fails (take snapshot)
            foreach (var publicEntry in delta.PublicEntries)
            {
                Execute(publicEntry, stateUpdate, txTracer, readOnly);
            }

            if (!readOnly)
            {
                // we should assign block rewards here (or in Ledger)
                _stateProvider.CommitTree();
                _storageProvider.CommitTrees();
            }
            else
            {
                _storageProvider.Reset();
                _stateProvider.Reset();
            }
        }
Beispiel #14
0
        public Block[] Process(Keccak branchStateRoot, Block[] suggestedBlocks, ProcessingOptions options, IBlockTracer blockTracer)
        {
            if (suggestedBlocks.Length == 0)
            {
                return(Array.Empty <Block>());
            }

            int stateSnapshot = _stateDb.TakeSnapshot();
            int codeSnapshot  = _codeDb.TakeSnapshot();

            if (stateSnapshot != -1 || codeSnapshot != -1)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Uncommitted state ({stateSnapshot}, {codeSnapshot}) when processing from a branch root {branchStateRoot} starting with block {suggestedBlocks[0].ToString(Block.Format.Short)}");
                }
            }

            Keccak snapshotStateRoot = _stateProvider.StateRoot;

            if (branchStateRoot != null && _stateProvider.StateRoot != branchStateRoot)
            {
                /* discarding the other branch data - chain reorganization */
                Metrics.Reorganizations++;
                _storageProvider.Reset();
                _stateProvider.Reset();
                _stateProvider.StateRoot = branchStateRoot;
            }

            var readOnly        = (options & ProcessingOptions.ReadOnlyChain) != 0;
            var processedBlocks = new Block[suggestedBlocks.Length];

            try
            {
                for (int i = 0; i < suggestedBlocks.Length; i++)
                {
                    processedBlocks[i] = ProcessOne(suggestedBlocks[i], options, blockTracer);
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Committing trees - state root {_stateProvider.StateRoot}");
                    }
                    _stateProvider.CommitTree();
                    _storageProvider.CommitTrees();

                    if (!readOnly)
                    {
                        BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(processedBlocks[i]));
                    }
                }

                if (readOnly)
                {
                    _receiptsTracer.BeforeRestore(_stateProvider);
                    Restore(stateSnapshot, codeSnapshot, snapshotStateRoot);
                }
                else
                {
                    _stateDb.Commit();
                    _codeDb.Commit();
                }

                return(processedBlocks);
            }
            catch (InvalidBlockException)
            {
                Restore(stateSnapshot, codeSnapshot, snapshotStateRoot);
                throw;
            }
        }
Beispiel #15
0
        private void LoadGenesisBlock(Keccak expectedGenesisHash)
        {
            // if we already have a database with blocks then we do not need to load genesis from spec
            if (_blockTree.Genesis != null)
            {
                ValidateGenesisHash(expectedGenesisHash);
                return;
            }

            Block genesis = _chainSpec.Genesis;

            CreateSystemAccounts();

            foreach ((Address address, ChainSpecAllocation allocation) in _chainSpec.Allocations)
            {
                _stateProvider.CreateAccount(address, allocation.Balance);
                if (allocation.Code != null)
                {
                    Keccak codeHash = _stateProvider.UpdateCode(allocation.Code);
                    _stateProvider.UpdateCodeHash(address, codeHash, _specProvider.GenesisSpec);
                }

                if (allocation.Constructor != null)
                {
                    Transaction constructorTransaction = new Transaction(true)
                    {
                        SenderAddress = address,
                        Init          = allocation.Constructor,
                        GasLimit      = genesis.GasLimit
                    };
                    _transactionProcessor.Execute(constructorTransaction, genesis.Header, NullTxTracer.Instance);
                }
            }

            _storageProvider.Commit();
            _stateProvider.Commit(_specProvider.GenesisSpec);

            _storageProvider.CommitTrees();
            _stateProvider.CommitTree();

            _dbProvider.StateDb.Commit();
            _dbProvider.CodeDb.Commit();

            genesis.StateRoot = _stateProvider.StateRoot;
            genesis.Hash      = BlockHeader.CalculateHash(genesis.Header);

            ManualResetEventSlim genesisProcessedEvent = new ManualResetEventSlim(false);

            bool genesisLoaded = false;

            void GenesisProcessed(object sender, BlockEventArgs args)
            {
                genesisLoaded            = true;
                _blockTree.NewHeadBlock -= GenesisProcessed;
                genesisProcessedEvent.Set();
            }

            _blockTree.NewHeadBlock += GenesisProcessed;
            _blockTree.SuggestBlock(genesis);
            genesisProcessedEvent.Wait(TimeSpan.FromSeconds(5));
            if (!genesisLoaded)
            {
                throw new BlockchainException("Genesis block processing failure");
            }

            ValidateGenesisHash(expectedGenesisHash);
        }