/// <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(); } }
/// <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); }
/// <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(); } }
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)); }
/// <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); }
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)}"); }
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); } } } }