예제 #1
0
        /// <inheritdoc/>
        public override BlockDigest?GetBlockDigest(HashDigest <SHA256> blockHash)
        {
            if (_blockCache.TryGetValue(blockHash, out BlockDigest cachedDigest))
            {
                return(cachedDigest);
            }

            byte[] key = BlockKey(blockHash);
            if (!(_blockIndexDb.Get(key) is byte[] blockDbNameBytes))
            {
                return(null);
            }

            _rwBlockLock.EnterReadLock();
            try
            {
                string blockDbName = RocksDBStoreBitConverter.GetString(blockDbNameBytes);
                if (!_blockDbCache.TryGetValue(blockDbName, out RocksDb blockDb))
                {
                    blockDb = RocksDBUtils.OpenRocksDb(_options, BlockDbPath(blockDbName));
                    _blockDbCache.AddOrUpdate(blockDbName, blockDb);
                }

                byte[] blockBytes = blockDb.Get(key);

                BlockDigest blockDigest = BlockDigest.Deserialize(blockBytes);

                _blockCache.AddOrUpdate(blockHash, blockDigest);
                return(blockDigest);
            }
            finally
            {
                _rwBlockLock.ExitReadLock();
            }
        }
예제 #2
0
        /// <inheritdoc/>
        public override void PutBlock <T>(Block <T> block)
        {
            if (_blockCache.ContainsKey(block.Hash))
            {
                return;
            }

            byte[] key = BlockKey(block.Hash);

            if (!(_blockDb.Get(key) is null))
            {
                return;
            }

            foreach (Transaction <T> tx in block.Transactions)
            {
                PutTransaction(tx);
            }

            BlockDigest digest = BlockDigest.FromBlock(block);

            byte[] value = digest.Serialize();
            _blockDb.Put(key, value);
            _blockCache.AddOrUpdate(block.Hash, digest);
        }
예제 #3
0
        /// <inheritdoc/>
        public override void PutBlock <T>(Block <T> block)
        {
            if (_blockCache.ContainsKey(block.Hash))
            {
                return;
            }

            byte[] key = BlockKey(block.Hash);

            if (!(_blockIndexDb.Get(key) is null))
            {
                return;
            }

            long timestamp = block.Timestamp.ToUnixTimeSeconds();

            foreach (Transaction <T> tx in block.Transactions)
            {
                PutTransaction(tx);
            }

            _rwBlockLock.EnterWriteLock();
            try
            {
                string  blockDbName = $"epoch{timestamp / _blockEpochUnitSeconds}";
                RocksDb blockDb;
                lock (_blockDbCache)
                {
                    if (!_blockDbCache.TryGetValue(blockDbName, out blockDb))
                    {
                        blockDb = RocksDBUtils.OpenRocksDb(_options, BlockDbPath(blockDbName));
                        _blockDbCache.AddOrUpdate(blockDbName, blockDb);
                    }
                }

                BlockDigest digest = BlockDigest.FromBlock(block);
                byte[]      value  = digest.Serialize();
                blockDb.Put(key, value);
                _blockIndexDb.Put(key, RocksDBStoreBitConverter.GetBytes(blockDbName));
                _blockCache.AddOrUpdate(block.Hash, digest);
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(PutBlock), e);
            }
            finally
            {
                _rwBlockLock.ExitWriteLock();
            }
        }
예제 #4
0
        public void PutBlock <T>(Block <T> block)
            where T : IAction, new()
        {
            if (_blockCache.ContainsKey(block.Hash))
            {
                return;
            }

            _store.PutBlock(block);
            foreach (var tx in block.Transactions)
            {
                PutTransaction(tx);
                StoreTxReferences(tx.Id, block.Hash, block.Index);
            }

            _blockCache.AddOrUpdate(block.Hash, BlockDigest.FromBlock(block));
        }
예제 #5
0
        /// <inheritdoc/>
        public override BlockDigest?GetBlockDigest(HashDigest <SHA256> blockHash)
        {
            if (_blockCache.TryGetValue(blockHash, out BlockDigest cachedDigest))
            {
                return(cachedDigest);
            }

            byte[] key   = BlockKey(blockHash);
            byte[] bytes = _blockDb.Get(key);

            if (bytes is null)
            {
                return(null);
            }

            BlockDigest blockDigest = BlockDigest.Deserialize(bytes);

            _blockCache.AddOrUpdate(blockHash, blockDigest);
            return(blockDigest);
        }
예제 #6
0
        private void ValidateReorgEnd(
            Block <T> oldTip,
            Block <T> newTip,
            Block <T> branchpoint)
        {
            if (!(BlockChain is BlockChain <T> chain))
            {
                return;
            }

            IBlockPolicy <T>           policy = chain.Policy;
            IStore                     store  = chain.Store;
            InvalidRenderException <T> heterogeneousGenesisError =
                Error(Records, "Reorg occurred from the chain with different genesis.");

            List <IAction>     expectedUnrenderedActions = new List <IAction>();
            BlockHeader        header = oldTip.Header;
            IEnumerable <TxId> txIds  = oldTip.Transactions.Select(tx => tx.Id);

            while (!header.Hash.Equals(branchpoint.Hash))
            {
                if (policy.BlockAction is IAction blockAction)
                {
                    expectedUnrenderedActions.Add(blockAction);
                }

                IEnumerable <Transaction <T> > transactions = txIds.Select(store.GetTransaction <T>);

                transactions = ActionEvaluator <T> .OrderTxsForEvaluation(
                    header.ProtocolVersion,
                    transactions,
                    header.PreEvaluationHash
                    );

                expectedUnrenderedActions.AddRange(
                    transactions.SelectMany(t => t.Actions).Cast <IAction>().Reverse());

                BlockDigest prevDigest = store.GetBlockDigest(
                    header.PreviousHash ?? throw heterogeneousGenesisError
                    ) ?? throw Error(Records, $"Failed to load block {header.PreviousHash}.");
                header = prevDigest.GetHeader(policy.GetHashAlgorithm);
                txIds  = prevDigest.TxIds.Select(b => new TxId(b.ToBuilder().ToArray()));
            }

            IEnumerable <IAction> expectedRenderedActionsBuffer = new List <IAction>();

            header = newTip.Header;
            txIds  = newTip.Transactions.Select(tx => tx.Id);
            while (!header.Hash.Equals(branchpoint.Hash))
            {
                IEnumerable <Transaction <T> > transactions = txIds.Select(store.GetTransaction <T>);
                transactions = ActionEvaluator <T> .OrderTxsForEvaluation(
                    header.ProtocolVersion,
                    transactions,
                    header.PreEvaluationHash
                    );

                IEnumerable <IAction> actions =
                    transactions.SelectMany(t => t.Actions).Cast <IAction>();
                if (policy.BlockAction is IAction blockAction)
                {
#if NET472 || NET471 || NET47 || NET462 || NET461
                    // Even though .NET Framework 4.6.1 or higher supports .NET Standard 2.0,
                    // versions lower than 4.8 lacks Enumerable.Append(IEnumerable<T>, T) method.
                    actions = actions.Concat(new IAction[] { blockAction });
#else
#pragma warning disable PC002
                    actions = actions.Append(blockAction);
#pragma warning restore PC002
#endif
                }

                expectedRenderedActionsBuffer = actions.Concat(expectedRenderedActionsBuffer);
                BlockDigest prevDigest = store.GetBlockDigest(
                    header.PreviousHash ?? throw heterogeneousGenesisError
                    ) ?? throw Error(Records, $"Failed to load block {header.PreviousHash}.");
                header = prevDigest.GetHeader(policy.GetHashAlgorithm);
                txIds  = prevDigest.TxIds.Select(b => new TxId(b.ToBuilder().ToArray()));
            }

            IAction[]      expectedRenderedActions = expectedRenderedActionsBuffer.ToArray();
            List <IAction> actualRenderedActions   = new List <IAction>();
            List <IAction> actualUnrenderedActions = new List <IAction>();
            foreach (var record in Records.Reverse())
            {
                if (record is RenderRecord <T> .Reorg b && b.Begin)
                {
                    break;
                }

                if (record is RenderRecord <T> .ActionBase a)
                {
                    if (a.Render)
                    {
                        actualRenderedActions.Add(a.Action);
                    }
                    else
                    {
                        actualUnrenderedActions.Add(a.Action);
                    }
                }
            }

            actualRenderedActions.Reverse();
            actualUnrenderedActions.Reverse();

            string ReprAction(IAction?action)
            {
                if (action is null)
                {
                    return("[N/A]");
                }

                return(action.PlainValue.Inspect(loadAll: true)
                       .Replace(" \n ", " ")
                       .Replace(" \n", " ")
                       .Replace("\n ", " ")
                       .Replace("\n", " "));
            }

            string MakeErrorMessage(string prefix, IList <IAction> expected, IList <IAction> actual)
            {
                int expectN = expected.Count;
                int actualN = actual.Count;

                if (expectN != actualN)
                {
                    prefix += $" (expected: {expectN} actions, actual: {actualN} actions):";
                }

                var buffer = new StringBuilder();

                for (int i = 0, count = Math.Max(expectN, actualN); i < count; i++)
                {
                    IAction?e = i < expectN ? expected[i] : null;
                    IAction?a = i < actualN ? actual[i] : null;
                    if (!(e is null || a is null) && e.PlainValue.Equals(a.PlainValue))
                    {
                        buffer.Append($"\n\t  {ReprAction(e)}");
                    }
예제 #7
0
        public void Balance(
            [Option('v', Description = "Print more logs.")]
            bool verbose,
            [Option('s', Description = "Path to the chain store.")]
            string storePath,
            [Option(
                 'b',
                 Description = "Optional block hash/index offset to query balances at.  " +
                               "Tip by default.")]
            string block = null,
            [Option('c', Description = "Optional chain ID.  Default is the canonical chain ID.")]
            Guid?chainId = null,
            [Argument(Description = "Account address.")]
            string address = null
            )
        {
            using Logger logger = Utils.ConfigureLogger(verbose);
            TextWriter stderr = Console.Error;

            (BlockChain <NCAction> chain, IStore store) =
                Utils.GetBlockChain(logger, storePath, chainId);

            Block <NCAction> offset = Utils.ParseBlockOffset(chain, block);

            stderr.WriteLine("The offset block: #{0} {1}.", offset.Index, offset.Hash);

            Bencodex.Types.Dictionary goldCurrencyStateDict = (Bencodex.Types.Dictionary)
                                                              chain.GetState(GoldCurrencyState.Address);
            GoldCurrencyState goldCurrencyState = new GoldCurrencyState(goldCurrencyStateDict);
            Currency          gold = goldCurrencyState.Currency;

            if (address is {} addrStr)
            {
                Address            addr    = Utils.ParseAddress(addrStr);
                FungibleAssetValue balance = chain.GetBalance(addr, gold, offset.Hash);
                Console.WriteLine("{0}\t{1}", addr, balance);
                return;
            }

            var printed = new HashSet <Address>();

            foreach (BlockHash blockHash in chain.BlockHashes)
            {
                BlockDigest digest = GetBlockDigest(store, blockHash);
                stderr.WriteLine("Scanning block #{0} {1}...", digest.Index, digest.Hash);
                stderr.Flush();
                IEnumerable <Address> addrs = digest.TxIds
                                              .Select(txId => store.GetTransaction <NCAction>(new TxId(txId.ToArray())))
                                              .SelectMany(tx => tx.Actions
                                                          .Select(a => a.InnerAction)
                                                          .SelectMany(a => a is TransferAsset t
                            ? new[] { t.Sender, t.Recipient }
                            : a is InitializeStates i &&
                                                                      i.GoldDistributions is Bencodex.Types.List l
                            ? l.OfType <Bencodex.Types.Dictionary>()
                                                                      .Select(d => new GoldDistribution(d).Address)
                            : new Address[0]))
                                              .Append(digest.Miner);
                foreach (Address addr in addrs)
                {
                    if (!printed.Contains(addr))
                    {
                        FungibleAssetValue balance = chain.GetBalance(addr, gold, offset.Hash);
                        Console.WriteLine("{0}\t{1}", addr, balance);
                        printed.Add(addr);
                    }
                }
            }
        }