Пример #1
0
        public void ForkFromChainWithDeletion()
        {
            IStore store  = Fx.Store;
            Guid   chainA = Guid.NewGuid();
            Guid   chainB = Guid.NewGuid();
            Guid   chainC = Guid.NewGuid();

            // We need `Block<T>`s because `IStore` can't retrive index(long) by block hash without
            // actual block...
            store.PutBlock(Fx.GenesisBlock);
            store.PutBlock(Fx.Block1);
            store.PutBlock(Fx.Block2);
            store.PutBlock(Fx.Block3);

            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);
            store.AppendIndex(chainA, Fx.Block1.Hash);
            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);
            store.DeleteChainId(chainA);

            store.ForkBlockIndexes(chainB, chainC, Fx.Block1.Hash);
            Assert.Equal(
                Fx.Block1.Hash,
                store.IndexBlockHash(chainC, Fx.Block1.Index)
                );
        }
Пример #2
0
        public void ForkWithBranch()
        {
            IStore store  = Fx.Store;
            Guid   chainA = Guid.NewGuid();
            Guid   chainB = Guid.NewGuid();

            // We need `Block<T>`s because `IStore` can't retrive index(long) by block hash without
            // actual block...
            Block <DumbAction> anotherBlock3 =
                MineNextBlock(Fx.Block2, Fx.GetHashAlgorithm, Fx.Miner);

            store.PutBlock(Fx.GenesisBlock);
            store.PutBlock(Fx.Block1);
            store.PutBlock(Fx.Block2);
            store.PutBlock(Fx.Block3);
            store.PutBlock(anotherBlock3);

            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);
            store.AppendIndex(chainA, Fx.Block1.Hash);
            store.AppendIndex(chainA, Fx.Block2.Hash);
            store.AppendIndex(chainA, Fx.Block3.Hash);

            store.ForkBlockIndexes(chainA, chainB, Fx.Block2.Hash);
            store.AppendIndex(chainB, anotherBlock3.Hash);

            Assert.Equal(
                new[]
            {
                Fx.Block2.Hash,
                anotherBlock3.Hash,
            },
                store.IterateIndexes(chainB, 2, 2)
                );
            Assert.Equal(
                new[]
            {
                Fx.Block2.Hash,
                anotherBlock3.Hash,
            },
                store.IterateIndexes(chainB, 2)
                );

            Assert.Equal(
                new[]
            {
                anotherBlock3.Hash,
            },
                store.IterateIndexes(chainB, 3, 1)
                );

            Assert.Equal(
                new[]
            {
                anotherBlock3.Hash,
            },
                store.IterateIndexes(chainB, 3)
                );
        }
Пример #3
0
        public static void Copy(this IStore from, IStore to)
        {
            // TODO: take a IProgress<> so that a caller can be aware the progress of cloning.
            if (to.ListChainIds().Any())
            {
                throw new ArgumentException("The destination store has to be empty.", nameof(to));
            }

            foreach (Guid chainId in from.ListChainIds().ToArray())
            {
                foreach (BlockHash blockHash in from.IterateIndexes(chainId))
                {
                    Block <NullAction> block = from.GetBlock <NullAction>(
                        _ => HashAlgorithmType.Of <SHA256>(),  // thunk getter; doesn't matter here
                        blockHash
                        );
                    to.PutBlock(block);
                    to.AppendIndex(chainId, blockHash);
                }

                foreach (KeyValuePair <Address, long> kv in from.ListTxNonces(chainId))
                {
                    to.IncreaseTxNonce(chainId, kv.Key, kv.Value);
                }
            }

            if (from.GetCanonicalChainId() is Guid canonId)
            {
                to.SetCanonicalChainId(canonId);
            }
        }
Пример #4
0
        public void PruneOutdatedChains()
        {
            IStore store = Fx.Store;

            store.PutBlock(Fx.GenesisBlock);
            store.PutBlock(Fx.Block1);
            store.PutBlock(Fx.Block2);
            store.PutBlock(Fx.Block3);

            Guid cid1 = Guid.NewGuid();

            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));
        }
Пример #5
0
        /// <summary>
        /// Makes a store, <paramref name="to"/>, logically (but not necessarily physically)
        /// identical to another store, <paramref name="from"/>.  As this copies the contents
        /// of the store, instead of its physicall data, this can be used for migrating
        /// between two different types of <see cref="IStore"/> implementations.
        /// </summary>
        /// <param name="from">The store containing the source contents.</param>
        /// <param name="to">The store to contain the copied contents. Expected to be empty.</param>
        /// <exception cref="ArgumentException">Thrown when the store passed through
        /// <paramref name="to"/> is not empty.</exception>
        public static void Copy(this IStore from, IStore to)
        {
            // TODO: take a IProgress<> so that a caller can be aware the progress of cloning.
            if (to.ListChainIds().Any())
            {
                throw new ArgumentException("The destination store has to be empty.", nameof(to));
            }

            foreach (Guid chainId in from.ListChainIds().ToArray())
            {
                foreach (HashDigest <SHA256> blockHash in from.IterateIndexes(chainId))
                {
                    Block <NullAction> block = from.GetBlock <NullAction>(blockHash);
                    to.PutBlock(block);
                    IImmutableDictionary <string, IValue> states = from.GetBlockStates(blockHash);
                    to.SetBlockStates(blockHash, states);
                    to.AppendIndex(chainId, blockHash);
                }

                foreach (KeyValuePair <Address, long> kv in from.ListTxNonces(chainId))
                {
                    to.IncreaseTxNonce(chainId, kv.Key, kv.Value);
                }

                foreach (string key in from.ListStateKeys(chainId))
                {
                    foreach (var pair in from.IterateStateReferences(chainId, key).Reverse())
                    {
                        pair.Deconstruct(out HashDigest <SHA256> refHash, out long refIndex);
                        to.StoreStateReference(
                            chainId,
                            ImmutableHashSet.Create(key),
                            refHash,
                            refIndex
                            );
                    }
                }
            }

            ImmutableHashSet <TxId> stagedTxIds =
                from.IterateStagedTransactionIds().ToImmutableHashSet();

            foreach (TxId txid in stagedTxIds)
            {
                to.PutTransaction(from.GetTransaction <NullAction>(txid));
            }

            to.StageTransactionIds(stagedTxIds);

            if (from.GetCanonicalChainId() is Guid canonId)
            {
                to.SetCanonicalChainId(canonId);
            }
        }
        public async Task Inspect(StoreType storeType)
        {
            Block <NCAction> genesisBlock = BlockChain <NCAction> .MakeGenesisBlock(
                HashAlgorithmType.Of <SHA256>()
                );

            IStore store   = storeType.CreateStore(_storePath2);
            Guid   chainId = Guid.NewGuid();

            store.SetCanonicalChainId(chainId);
            store.PutBlock(genesisBlock);
            store.AppendIndex(chainId, genesisBlock.Hash);
            var stateStore = new TrieStateStore(new DefaultKeyValueStore(null));

            IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >();
            IBlockPolicy <NCAction> blockPolicy = new BlockPolicySource(Logger.None).GetPolicy();
            BlockChain <NCAction>   chain       = new BlockChain <NCAction>(
                blockPolicy,
                stagePolicy,
                store,
                stateStore,
                genesisBlock);

            var action = new HackAndSlash
            {
                costumes      = new List <Guid>(),
                equipments    = new List <Guid>(),
                foods         = new List <Guid>(),
                worldId       = 1,
                stageId       = 1,
                avatarAddress = default
            };

            var minerKey = new PrivateKey();

            chain.MakeTransaction(minerKey, new PolymorphicAction <ActionBase>[] { action });
            await chain.MineBlock(minerKey, DateTimeOffset.Now);

            store.Dispose();

            _command.Inspect(storeType, _storePath2);
            List <double> output = _console.Out.ToString().Split("\n")[1]
                                   .Split(',').Select(double.Parse).ToList();
            var totalTxCount      = Convert.ToInt32(output[2]);
            var hackandslashCount = Convert.ToInt32(output[3]);

            Assert.Equal(1, totalTxCount);
            Assert.Equal(1, hackandslashCount);
        }
Пример #7
0
        public void GetGenesisBlock(StoreType storeType)
        {
            IStore           store        = storeType.CreateStore(_storePath);
            Block <NCAction> genesisBlock = BlockChain <NCAction> .MakeGenesisBlock();

            Guid chainId = Guid.NewGuid();

            store.SetCanonicalChainId(chainId);
            store.PutBlock(genesisBlock);
            store.AppendIndex(chainId, genesisBlock.Hash);

            Assert.Equal(genesisBlock, store.GetGenesisBlock <NCAction>());

            (store as IDisposable)?.Dispose();
        }
Пример #8
0
        public void Tip(StoreType storeType)
        {
            Block <NCAction> genesisBlock = BlockChain <NCAction> .MakeGenesisBlock();

            IStore store   = storeType.CreateStore(_storePath);
            Guid   chainId = Guid.NewGuid();

            store.SetCanonicalChainId(chainId);
            store.PutBlock(genesisBlock);
            store.AppendIndex(chainId, genesisBlock.Hash);
            (store as IDisposable)?.Dispose();

            _command.Tip(storeType, _storePath);

            Assert.Equal(JsonSerializer.Serialize(genesisBlock.Header) + "\n", _console.Out.ToString());
        }
Пример #9
0
        /// <summary>
        /// Makes a store, <paramref name="to"/>, logically (but not necessarily physically)
        /// identical to another store, <paramref name="from"/>.  As this copies the contents
        /// of the store, instead of its physicall data, this can be used for migrating
        /// between two different types of <see cref="IStore"/> implementations.
        /// </summary>
        /// <param name="from">The store containing the source contents.</param>
        /// <param name="to">The store to contain the copied contents. Expected to be empty.</param>
        /// <exception cref="ArgumentException">Thrown when the store passed through
        /// <paramref name="to"/> is not empty.</exception>
        public static void Copy(this IStore from, IStore to)
        {
            // TODO: take a IProgress<> so that a caller can be aware the progress of cloning.
            if (to.ListChainIds().Any())
            {
                throw new ArgumentException("The destination store has to be empty.", nameof(to));
            }

            foreach (Guid chainId in from.ListChainIds().ToArray())
            {
                foreach (BlockHash blockHash in from.IterateIndexes(chainId))
                {
                    Block <NullAction> block = from.GetBlock <NullAction>(blockHash);
                    to.PutBlock(block);
                    to.AppendIndex(chainId, blockHash);
                }

                foreach (KeyValuePair <Address, long> kv in from.ListTxNonces(chainId))
                {
                    to.IncreaseTxNonce(chainId, kv.Key, kv.Value);
                }
            }

            ImmutableHashSet <TxId> stagedTxIds =
                from.IterateStagedTransactionIds().ToImmutableHashSet();

            foreach (TxId txid in stagedTxIds)
            {
                to.PutTransaction(from.GetTransaction <NullAction>(txid));
            }

            to.StageTransactionIds(stagedTxIds);

            if (from.GetCanonicalChainId() is Guid canonId)
            {
                to.SetCanonicalChainId(canonId);
            }
        }
        public void Tip(StoreType storeType)
        {
            HashAlgorithmType hashAlgo     = HashAlgorithmType.Of <SHA256>();
            Block <NCAction>  genesisBlock = BlockChain <NCAction> .MakeGenesisBlock(hashAlgo);

            IStore store   = storeType.CreateStore(_storePath);
            Guid   chainId = Guid.NewGuid();

            store.SetCanonicalChainId(chainId);
            store.PutBlock(genesisBlock);
            store.AppendIndex(chainId, genesisBlock.Hash);
            store.Dispose();

            // FIXME For an unknown reason, BlockHeader.TimeStamp precision issue occurred and the store we should open it again.
            store        = storeType.CreateStore(_storePath);
            genesisBlock = store.GetBlock <NCAction>(_ => hashAlgo, genesisBlock.Hash);
            store.Dispose();

            _command.Tip(storeType, _storePath);
            Assert.Equal(
                Utils.SerializeHumanReadable(genesisBlock.Header),
                _console.Out.ToString().Trim()
                );
        }
Пример #11
0
 /// <inheritdoc cref="IStore.AppendIndex(Guid, BlockHash)"/>
 public long AppendIndex(Guid chainId, BlockHash hash) =>
 _store.AppendIndex(chainId, hash);
Пример #12
0
        public void ForkBlockIndex()
        {
            IStore store  = Fx.Store;
            Guid   chainA = Guid.NewGuid();
            Guid   chainB = Guid.NewGuid();
            Guid   chainC = Guid.NewGuid();

            // We need `Block<T>`s because `IStore` can't retrive index(long) by block hash without
            // actual block...
            store.PutBlock(Fx.GenesisBlock);
            store.PutBlock(Fx.Block1);
            store.PutBlock(Fx.Block2);
            store.PutBlock(Fx.Block3);

            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);
            store.AppendIndex(chainB, Fx.GenesisBlock.Hash);
            store.AppendIndex(chainC, Fx.GenesisBlock.Hash);

            store.AppendIndex(chainA, Fx.Block1.Hash);
            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);
            store.AppendIndex(chainB, Fx.Block2.Hash);

            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
            },
                store.IterateIndexes(chainA)
                );
            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
                Fx.Block2.Hash,
            },
                store.IterateIndexes(chainB)
                );

            store.ForkBlockIndexes(chainB, chainC, Fx.Block2.Hash);
            store.AppendIndex(chainC, Fx.Block3.Hash);

            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
            },
                store.IterateIndexes(chainA)
                );
            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
                Fx.Block2.Hash,
            },
                store.IterateIndexes(chainB)
                );
            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
                Fx.Block2.Hash,
                Fx.Block3.Hash,
            },
                store.IterateIndexes(chainC)
                );

            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainA, 1));
            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainB, 1));
            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainC, 1));
            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainB, 2));
            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainC, 2));
            Assert.Equal(Fx.Block3.Hash, store.IndexBlockHash(chainC, 3));

            Assert.Throws <ChainIdNotFoundException>(
                () => store.ForkBlockIndexes(Guid.NewGuid(), Guid.NewGuid(), Fx.Block2.Hash)
                );
        }
Пример #13
0
        public void DeleteChainIdWithForksReverse()
        {
            IStore store  = Fx.Store;
            Guid   chainA = Guid.NewGuid();
            Guid   chainB = Guid.NewGuid();
            Guid   chainC = Guid.NewGuid();

            // We need `Block<T>`s because `IStore` can't retrive index(long) by block hash without
            // actual block...
            store.PutBlock(Fx.GenesisBlock);
            store.PutBlock(Fx.Block1);
            store.PutBlock(Fx.Block2);
            store.PutBlock(Fx.Block3);

            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);
            store.AppendIndex(chainB, Fx.GenesisBlock.Hash);
            store.AppendIndex(chainC, Fx.GenesisBlock.Hash);

            store.AppendIndex(chainA, Fx.Block1.Hash);
            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);
            store.AppendIndex(chainB, Fx.Block2.Hash);
            store.ForkBlockIndexes(chainB, chainC, Fx.Block2.Hash);
            store.AppendIndex(chainC, Fx.Block3.Hash);

            store.DeleteChainId(chainC);

            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
            },
                store.IterateIndexes(chainA)
                );
            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
                Fx.Block2.Hash,
            },
                store.IterateIndexes(chainB)
                );
            Assert.Empty(store.IterateIndexes(chainC));

            store.DeleteChainId(chainB);

            Assert.Equal(
                new[]
            {
                Fx.GenesisBlock.Hash,
                Fx.Block1.Hash,
            },
                store.IterateIndexes(chainA)
                );
            Assert.Empty(store.IterateIndexes(chainB));
            Assert.Empty(store.IterateIndexes(chainC));

            store.DeleteChainId(chainA);
            Assert.Empty(store.IterateIndexes(chainA));
            Assert.Empty(store.IterateIndexes(chainB));
            Assert.Empty(store.IterateIndexes(chainC));
        }
Пример #14
0
 public long AppendIndex(Guid chainId, HashDigest <SHA256> hash)
 {
     Log(nameof(AppendIndex), chainId, hash);
     return(_store.AppendIndex(chainId, hash));
 }
Пример #15
0
 public long AppendIndex(Guid chainId, BlockHash hash)
 {
     Log(nameof(AppendIndex), chainId, hash);
     return(_store.AppendIndex(chainId, hash));
 }
Пример #16
0
 /// <inheritdoc cref="IStore"/>
 public long AppendIndex(Guid chainId, HashDigest <SHA256> hash)
 {
     return(_store.AppendIndex(chainId, hash));
 }