) GetBlockChain( ILogger logger, string storePath, Guid?chainId = null, IKeyValueStore stateKeyValueStore = null ) { var policySource = new BlockPolicySource(logger); IBlockPolicy <NCAction> policy = policySource.GetPolicy(); IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <NCAction>(); IStore store = new RocksDBStore(storePath); if (stateKeyValueStore is null) { stateKeyValueStore = new RocksDBKeyValueStore(Path.Combine(storePath, "states")); } IStateStore stateStore = new TrieStateStore(stateKeyValueStore); Guid chainIdValue = chainId ?? store.GetCanonicalChainId() ?? throw new CommandExitedException( "No canonical chain ID. Available chain IDs:\n " + string.Join <Guid>("\n ", store.ListChainIds()), 1); BlockHash genesisBlockHash; try { genesisBlockHash = store.IterateIndexes(chainIdValue).First(); } catch (InvalidOperationException) { throw new CommandExitedException( $"The chain {chainIdValue} seems empty; try with another chain ID:\n " + string.Join <Guid>("\n ", store.ListChainIds()), 1 ); } Block <NCAction> genesis = store.GetBlock <NCAction>( policy.GetHashAlgorithm, genesisBlockHash ); BlockChain <NCAction> chain = new BlockChain <NCAction>( policy, stagePolicy, store, stateStore, genesis ); return(chain, store, stateKeyValueStore, stateStore); }
static void Main(string[] args) { if (args.Length < 2) { Console.Error.WriteLine("Too few arguments."); Environment.Exit(1); return; } string storePath = args[0]; int limit = int.Parse(args[1]); int offset = 0; if (args.Length >= 3) { offset = int.Parse(args[2]); } if (limit < 0) { Console.Error.WriteLine("Limit value must be greater than 0. Entered value: {0}", limit); Environment.Exit(1); return; } if (offset < 0) { Console.Error.WriteLine("Offset value must be greater than 0. Entered value: {0}", offset); Environment.Exit(1); return; } Log.Logger = new LoggerConfiguration().MinimumLevel.Verbose().WriteTo.Console().CreateLogger(); Libplanet.Crypto.CryptoConfig.CryptoBackend = new Secp256K1CryptoBackend <SHA256>(); var policySource = new BlockPolicySource(Log.Logger, LogEventLevel.Verbose); IBlockPolicy <NCAction> policy = policySource.GetPolicy( // Explicitly set to lowest possible difficulty. minimumDifficulty: BlockPolicySource.DifficultyStability, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: null, maxTransactionsPerSignerPerBlockPolicy: null, authorizedMinersPolicy: null, permissionedMinersPolicy: null); IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <NCAction>(); var store = new RocksDBStore(storePath); if (!(store.GetCanonicalChainId() is Guid chainId)) { Console.Error.WriteLine("There is no canonical chain: {0}", storePath); Environment.Exit(1); return; } if (!(store.IndexBlockHash(chainId, 0) is { } gHash)) { Console.Error.WriteLine("There is no genesis block: {0}", storePath); Environment.Exit(1); return; } DateTimeOffset started = DateTimeOffset.UtcNow; Block <NCAction> genesis = store.GetBlock <NCAction>(policy.GetHashAlgorithm, gHash); IKeyValueStore stateKeyValueStore = new RocksDBKeyValueStore(Path.Combine(storePath, "states")); var stateStore = new TrieStateStore(stateKeyValueStore); var chain = new BlockChain <NCAction>(policy, stagePolicy, store, stateStore, genesis); long height = chain.Tip.Index; if (offset + limit > (int)height) { Console.Error.WriteLine( "The sum of the offset and limit is greater than the chain tip index: {0}", height); Environment.Exit(1); return; } BlockHash[] blockHashes = store.IterateIndexes(chain.Id, offset, limit).Select((value, i) => value).ToArray(); Console.Error.WriteLine( "Executing {0} blocks: {1}-{2} (inclusive).", blockHashes.Length, blockHashes[0], blockHashes.Last() ); Block <NCAction>[] blocks = blockHashes.Select(h => chain[h]).ToArray(); DateTimeOffset blocksLoaded = DateTimeOffset.UtcNow; long txs = 0; long actions = 0; foreach (Block <NCAction> block in blocks) { Console.Error.WriteLine( "Block #{0} {1}; {2} txs", block.Index, block.Hash, block.Transactions.Count() ); IEnumerable <ActionEvaluation> blockEvals = chain.ExecuteActions(block, StateCompleterSet <NCAction> .Reject); SetStates( chain.Id, store, stateStore, block, blockEvals.ToArray(), buildStateReferences: true ); txs += block.Transactions.LongCount(); actions += block.Transactions.Sum(tx => tx.Actions.LongCount()) + 1; } DateTimeOffset ended = DateTimeOffset.UtcNow; Console.WriteLine("Loading blocks\t{0}", blocksLoaded - started); long execActionsTotalMilliseconds = (long)(ended - blocksLoaded).TotalMilliseconds; Console.WriteLine("Executing actions\t{0}ms", execActionsTotalMilliseconds); Console.WriteLine("Average per block\t{0}ms", execActionsTotalMilliseconds / blockHashes.Length); Console.WriteLine("Average per tx\t{0}ms", execActionsTotalMilliseconds / txs); Console.WriteLine("Average per action\t{0}ms", execActionsTotalMilliseconds / actions); Console.WriteLine("Total elapsed\t{0}", ended - started); }
public void PruneOutdatedChainsRocksDb() { var path = Path.Combine(Path.GetTempPath(), $"rocksdb_test_{Guid.NewGuid()}"); var store = new RocksDBStore(path); RocksDb chainDb = null; int KeysWithChainId(RocksDb db, Guid cid) { using (Iterator it = db.NewIterator()) { byte[] key = cid.ToByteArray(); int count = 0; for (it.SeekToFirst(); it.Valid(); it.Next()) { if (!it.Key().Skip(1).ToArray().StartsWith(key)) { continue; } count++; } return(count); } } try { store.PutBlock(Fx.GenesisBlock); store.PutBlock(Fx.Block1); store.PutBlock(Fx.Block2); store.PutBlock(Fx.Block3); Guid cid1 = Guid.NewGuid(); int guidLength = cid1.ToByteArray().Length; store.AppendIndex(cid1, Fx.GenesisBlock.Hash); store.AppendIndex(cid1, Fx.Block1.Hash); store.AppendIndex(cid1, Fx.Block2.Hash); Assert.Single(store.ListChainIds()); Assert.Equal( new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash }, store.IterateIndexes(cid1, 0, null)); Guid cid2 = Guid.NewGuid(); store.ForkBlockIndexes(cid1, cid2, Fx.Block1.Hash); store.AppendIndex(cid2, Fx.Block2.Hash); store.AppendIndex(cid2, Fx.Block3.Hash); Assert.Equal(2, store.ListChainIds().Count()); Assert.Equal( new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash, Fx.Block3.Hash }, store.IterateIndexes(cid2, 0, null)); Guid cid3 = Guid.NewGuid(); store.ForkBlockIndexes(cid1, cid3, Fx.Block2.Hash); Assert.Equal(3, store.ListChainIds().Count()); Assert.Equal( new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash }, store.IterateIndexes(cid3, 0, null)); Assert.Throws <InvalidOperationException>(() => store.PruneOutdatedChains()); store.PruneOutdatedChains(true); store.SetCanonicalChainId(cid3); store.PruneOutdatedChains(); Assert.Single(store.ListChainIds()); Assert.Equal( new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash }, store.IterateIndexes(cid3, 0, null)); Assert.Equal(3, store.CountIndex(cid3)); store.Dispose(); store = null; chainDb = RocksDb.Open(new DbOptions(), Path.Combine(path, "chain")); Assert.Equal(0, KeysWithChainId(chainDb, cid1)); Assert.Equal(0, KeysWithChainId(chainDb, cid2)); Assert.NotEqual(0, KeysWithChainId(chainDb, cid3)); } finally { store?.Dispose(); chainDb?.Dispose(); Directory.Delete(path, true); } }