public void Tip( [Argument("STORE-TYPE")] StoreType storeType, [Argument("STORE-PATH")] string storePath) { if (!Directory.Exists(storePath)) { throw new CommandExitedException($"The given STORE-PATH, {storePath} seems not existed.", -1); } const int minimumDifficulty = 5000000, maximumTransactions = 100; IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); IBlockPolicy <NCAction> blockPolicy = new BlockPolicySource(Logger.None).GetPolicy(minimumDifficulty, maximumTransactions); IStore store = storeType.CreateStore(storePath); Block <NCAction> genesisBlock = store.GetGenesisBlock <NCAction>(); BlockChain <NCAction> chain = new BlockChain <NCAction>( blockPolicy, stagePolicy, store, new NoOpStateStore(), genesisBlock); _console.Out.WriteLine(JsonSerializer.Serialize(chain.Tip.Header)); }
public void Tip( [Argument("STORE-TYPE")] StoreType storeType, [Argument("STORE-PATH")] string storePath) { if (!Directory.Exists(storePath)) { throw new CommandExitedException($"The given STORE-PATH, {storePath} seems not existed.", -1); } IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); IBlockPolicy <NCAction> blockPolicy = new BlockPolicySource(Logger.None).GetPolicy(); IStore store = storeType.CreateStore(storePath); var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); Block <NCAction> genesisBlock = store.GetGenesisBlock <NCAction>(blockPolicy.GetHashAlgorithm); BlockChain <NCAction> chain = new BlockChain <NCAction>( blockPolicy, stagePolicy, store, stateStore, genesisBlock); _console.Out.WriteLine(Utils.SerializeHumanReadable(chain.Tip.Header)); (store as IDisposable)?.Dispose(); }
public void DoesTransactionFollowsPolicyWithEmpty() { var adminPrivateKey = new PrivateKey(); var adminAddress = new Address(adminPrivateKey.PublicKey); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy(10000, 100); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock(adminAddress, ImmutableHashSet <Address> .Empty); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null), new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Transaction <PolymorphicAction <ActionBase> > tx = Transaction <PolymorphicAction <ActionBase> > .Create( 0, new PrivateKey(), genesis.Hash, new PolymorphicAction <ActionBase>[] { }); Assert.True(policy.DoesTransactionFollowsPolicy(tx, blockChain)); }
public StagePolicy(TimeSpan txLifeTime, int quotaPerSigner) { _txs = new ConcurrentDictionary <Address, SortedList <Transaction <NCAction>, TxId> >(); _quotaPerSigner = quotaPerSigner; _impl = (txLifeTime == default) ? new VolatileStagePolicy <NCAction>() : new VolatileStagePolicy <NCAction>(txLifeTime); }
public void ValidateNextBlockTxWithAuthorizedMiners() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var authorizedMinerPrivateKey = new PrivateKey(); (ActivationKey ak, PendingActivationState ps) = ActivationKey.Create( new PrivateKey(), new byte[] { 0x00, 0x01 } ); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( minimumDifficulty: 10_000, hashAlgorithmTypePolicy: null, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: null, maxTransactionsPerSignerPerBlockPolicy: null, authorizedMinersPolicy: AuthorizedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 0, endIndex: 10, filter: index => index % 5 == 0, value: new Address[] { authorizedMinerPrivateKey.ToAddress() } .ToImmutableHashSet())), permissionedMinersPolicy: null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet.Create(adminAddress), pendingActivations: new[] { ps } ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Transaction <PolymorphicAction <ActionBase> > txFromAuthorizedMiner = Transaction <PolymorphicAction <ActionBase> > .Create( 0, authorizedMinerPrivateKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { ak.CreateActivateAccount(new byte[] { 0x00, 0x01 }) } ); // Deny tx even if contains valid activation key. Assert.NotNull(policy.ValidateNextBlockTx(blockChain, txFromAuthorizedMiner)); }
public static (BlockChain <NCAction> Chain, IStore Store) GetBlockChain( ILogger logger, string storePath, bool monorocksdb = false, Guid?chainId = null ) { var policySource = new BlockPolicySource(logger); IBlockPolicy <NCAction> policy = policySource.GetPolicy(); IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <NCAction>(); IStore store = monorocksdb ? (IStore) new MonoRocksDBStore(storePath) : new RocksDBStore(storePath); IKeyValueStore 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("\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("\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); }
public void Evaluate() { Address address = _contents.Tx0InBlock1.Signer; var blockAction = new SetStatesAtBlock(address, (Bencodex.Types.Integer) 123, 0); var policy = new BlockPolicy <Arithmetic>( blockAction: blockAction, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000), minimumDifficulty: 2, difficultyStability: 1 ); var stagePolicy = new VolatileStagePolicy <Arithmetic>(); PreEvaluationBlock <Arithmetic> preEvalGenesis = _contents.Genesis.Mine(policy.GetHashAlgorithm(0)); using (var fx = new DefaultStoreFixture()) { Block <Arithmetic> genesis = preEvalGenesis.Evaluate(_contents.GenesisKey, blockAction, fx.StateStore); AssertPreEvaluationBlocksEqual(preEvalGenesis, genesis); _output.WriteLine("#1: {0}", genesis); var blockChain = new BlockChain <Arithmetic>( policy, stagePolicy, fx.Store, fx.StateStore, genesis ); AssertBencodexEqual((Bencodex.Types.Integer) 123, blockChain.GetState(address)); HashDigest <SHA256> identicalGenesisStateRootHash = preEvalGenesis.DetermineStateRootHash(blockChain); AssertBytesEqual(genesis.StateRootHash, identicalGenesisStateRootHash); BlockContent <Arithmetic> content1 = _contents.Block1; content1.PreviousHash = genesis.Hash; content1.Difficulty = 2; content1.Transactions = new[] { _contents.Tx0InBlock1 }; PreEvaluationBlock <Arithmetic> preEval1 = content1.Mine(policy.GetHashAlgorithm(1)); Block <Arithmetic> block1 = preEval1.Evaluate(_contents.Block1Key, blockChain); AssertPreEvaluationBlocksEqual(preEval1, block1); _output.WriteLine("#1: {0}", block1); HashDigest <SHA256> identicalBlock1StateRootHash = preEval1.DetermineStateRootHash(blockChain); AssertBytesEqual(block1.StateRootHash, identicalBlock1StateRootHash); blockChain.Append(block1); AssertBencodexEqual((Bencodex.Types.Integer) 158, blockChain.GetState(address)); } }
public StagePolicy(TimeSpan txLifeTime, int quotaPerSigner) { if (quotaPerSigner < 1) { throw new ArgumentOutOfRangeException( $"{nameof(quotaPerSigner)} must be positive: ${quotaPerSigner}"); } _txs = new ConcurrentDictionary <Address, SortedList <Transaction <NCAction>, TxId> >(); _quotaPerSigner = quotaPerSigner; _impl = (txLifeTime == default) ? new VolatileStagePolicy <NCAction>() : new VolatileStagePolicy <NCAction>(txLifeTime); }
public async void EarnMiningGoldWhenSuccessMining() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var authorizedMinerPrivateKey = new PrivateKey(); (ActivationKey ak, PendingActivationState ps) = ActivationKey.Create( new PrivateKey(), new byte[] { 0x00, 0x01 } ); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( 10_000, null, null, null, null, null, null, null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet.Create(adminAddress), new AuthorizedMinersState( new[] { authorizedMinerPrivateKey.ToAddress() }, 5, 10 ), pendingActivations: new[] { ps } ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); await blockChain.MineBlock(adminPrivateKey); FungibleAssetValue actualBalance = blockChain.GetBalance(adminAddress, _currency); FungibleAssetValue expectedBalance = new FungibleAssetValue(_currency, 10, 0); Assert.True(expectedBalance.Equals(actualBalance)); }
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); }
public void DoesTransactionFollowsPolicyWithAuthorizedMiners() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var authorizedMinerPrivateKey = new PrivateKey(); (ActivationKey ak, PendingActivationState ps) = ActivationKey.Create( new PrivateKey(), new byte[] { 0x00, 0x01 } ); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy(10000, 100); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet.Create(adminAddress), new AuthorizedMinersState( new[] { authorizedMinerPrivateKey.ToAddress() }, 5, 10 ), pendingActivations: new[] { ps } ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null), new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Transaction <PolymorphicAction <ActionBase> > txFromAuthorizedMiner = Transaction <PolymorphicAction <ActionBase> > .Create( 0, authorizedMinerPrivateKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { ak.CreateActivateAccount(new byte[] { 0x00, 0x01 }) } ); // Deny tx even if contains valid activation key. Assert.False(policy.DoesTransactionFollowsPolicy(txFromAuthorizedMiner, blockChain)); }
public void MustNotIncludeBlockActionAtTransaction() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var authorizedMinerPrivateKey = new PrivateKey(); (ActivationKey ak, PendingActivationState ps) = ActivationKey.Create( new PrivateKey(), new byte[] { 0x00, 0x01 } ); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( 10_000, null, null, null, null, null, null, null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet.Create(adminAddress), new AuthorizedMinersState( new[] { authorizedMinerPrivateKey.ToAddress() }, 5, 10 ), pendingActivations: new[] { ps } ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Assert.Throws <MissingActionTypeException>(() => { blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new RewardGold() } ); }); }
public async Task GetNextBlockDifficultyWithAuthorizedMinersPolicy() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var minerKey = new PrivateKey(); var miners = new[] { minerKey.ToAddress() }; var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( minimumDifficulty: 4096, hashAlgorithmTypePolicy: null, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: null, maxTransactionsPerSignerPerBlockPolicy: null, authorizedMinersPolicy: AuthorizedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 0, endIndex: 6, filter: index => index % 2 == 0, value: miners.ToImmutableHashSet())), permissionedMinersPolicy: null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet <Address> .Empty); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); var minerObj = new Miner(blockChain, null, minerKey); var dateTimeOffset = DateTimeOffset.MinValue; // Index 1 Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 2, target index Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); minerObj.StageProofTransaction(); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 3 Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 4, target index Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); minerObj.StageProofTransaction(); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 5 Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 6, target index Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); minerObj.StageProofTransaction(); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 7 Assert.Equal(4098, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 8 Assert.Equal(4100, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 9 Assert.Equal(4102, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 10 Assert.Equal(4104, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 11 Assert.Equal(4106, policy.GetNextBlockDifficulty(blockChain)); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); dateTimeOffset += TimeSpan.FromSeconds(20); await blockChain.MineBlock(minerKey, dateTimeOffset); // Index 12 Assert.Equal(4104, policy.GetNextBlockDifficulty(blockChain)); }
public async Task ValidateNextBlockWithAuthorizedMinersPolicy() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var minerKeys = new[] { new PrivateKey(), new PrivateKey() }; Address[] miners = minerKeys.Select(AddressExtensions.ToAddress).ToArray(); var stranger = new PrivateKey(); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( minimumDifficulty: 10_000, hashAlgorithmTypePolicy: null, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: null, maxTransactionsPerSignerPerBlockPolicy: null, authorizedMinersPolicy: AuthorizedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 0, endIndex: 4, filter: index => index % 2 == 0, value: miners.ToImmutableHashSet())), permissionedMinersPolicy: null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet <Address> .Empty); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); // Index 1. Anyone can mine. await blockChain.MineBlock(stranger); // Index 2. Only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>(async() => { await blockChain.MineBlock(stranger); }); // Old proof mining still works. new Miner(blockChain, null, minerKeys[0]).StageProofTransaction(); await blockChain.MineBlock(minerKeys[0]); // Index 3. Anyone can mine. blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); await blockChain.MineBlock(stranger); // Index 4. Again, only authorized miner can mine. blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); await Assert.ThrowsAsync <BlockPolicyViolationException>(async() => { await blockChain.MineBlock(stranger); }); // No proof is required. blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); await blockChain.MineBlock(minerKeys[1]); // Index 5, 6. Anyone can mine. await blockChain.MineBlock(stranger); blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new DailyReward(), } ); await blockChain.MineBlock(stranger); }
public async Task GetNextBlockDifficultyWithAuthorizedMinersState() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var minerKey = new PrivateKey(); var miner = minerKey.ToAddress(); var miners = new[] { miner }; var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy(4096, 100); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet <Address> .Empty, new AuthorizedMinersState(miners, 2, 6) ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null), new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); var minerObj = new Miner(blockChain, null, minerKey, true); if (policy is BlockPolicy bp) { bp.AuthorizedMinersState = new AuthorizedMinersState( (Dictionary)blockChain.GetState(AuthorizedMinersState.Address) ); } var dateTimeOffset = DateTimeOffset.MinValue; // Index 1 Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 2, target index Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); minerObj.StageProofTransaction(); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 3 Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 4, target index Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); minerObj.StageProofTransaction(); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 5 Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 6, target index Assert.Equal(4096, policy.GetNextBlockDifficulty(blockChain)); minerObj.StageProofTransaction(); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 7 Assert.Equal(4098, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 8 Assert.Equal(4100, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 9 Assert.Equal(4102, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 10 Assert.Equal(4104, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(1); await blockChain.MineBlock(miner, dateTimeOffset); // Index 11 Assert.Equal(4106, policy.GetNextBlockDifficulty(blockChain)); dateTimeOffset += TimeSpan.FromSeconds(20); await blockChain.MineBlock(miner, dateTimeOffset); // Index 12 Assert.Equal(4104, policy.GetNextBlockDifficulty(blockChain)); }
public void ValidateNextBlockWithManyTransactions() { var adminPrivateKey = new PrivateKey(); var adminAddress = new Address(adminPrivateKey.PublicKey); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy(3000, 10); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock(adminAddress, ImmutableHashSet <Address> .Empty); using var store = new DefaultStore(null); var stateStore = new NoOpStateStore(); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis ); int nonce = 0; List <Transaction <PolymorphicAction <ActionBase> > > GenerateTransactions(int count) { var list = new List <Transaction <PolymorphicAction <ActionBase> > >(); for (int i = 0; i < count; i++) { list.Add(Transaction <PolymorphicAction <ActionBase> > .Create( nonce++, adminPrivateKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { } )); } return(list); } Assert.Equal(1, blockChain.Count); Block <PolymorphicAction <ActionBase> > block1 = Block <PolymorphicAction <ActionBase> > .Mine( index : 1, difficulty : policy.GetNextBlockDifficulty(blockChain), previousTotalDifficulty : blockChain.Tip.TotalDifficulty, miner : adminAddress, previousHash : blockChain.Tip.Hash, timestamp : DateTimeOffset.MinValue, transactions : GenerateTransactions(5)); blockChain.Append(block1); Assert.Equal(2, blockChain.Count); Assert.True(blockChain.ContainsBlock(block1.Hash)); Block <PolymorphicAction <ActionBase> > block2 = Block <PolymorphicAction <ActionBase> > .Mine( index : 2, difficulty : policy.GetNextBlockDifficulty(blockChain), previousTotalDifficulty : blockChain.Tip.TotalDifficulty, miner : adminAddress, previousHash : blockChain.Tip.Hash, timestamp : DateTimeOffset.MinValue, transactions : GenerateTransactions(10)); blockChain.Append(block2); Assert.Equal(3, blockChain.Count); Assert.True(blockChain.ContainsBlock(block2.Hash)); Block <PolymorphicAction <ActionBase> > block3 = Block <PolymorphicAction <ActionBase> > .Mine( index : 3, difficulty : policy.GetNextBlockDifficulty(blockChain), previousTotalDifficulty : blockChain.Tip.TotalDifficulty, miner : adminAddress, previousHash : blockChain.Tip.Hash, timestamp : DateTimeOffset.MinValue, transactions : GenerateTransactions(11)); Assert.Throws <BlockExceedingTransactionsException>(() => blockChain.Append(block3)); Assert.Equal(3, blockChain.Count); Assert.False(blockChain.ContainsBlock(block3.Hash)); }
public void Inspect( [Argument("STORE-TYPE", Description = "Store type of RocksDb (rocksdb or monorocksdb).")] StoreType storeType, [Argument("STORE-PATH", Description = "Store path to inspect.")] string storePath, [Argument("OFFSET", Description = "Offset of block index.")] int?offset = null, [Argument("LIMIT", Description = "Limit of block count.")] int?limit = null) { if (!Directory.Exists(storePath)) { throw new CommandExitedException($"The given STORE-PATH, {storePath} seems not existed.", -1); } IStagePolicy <NCAction> stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); IBlockPolicy <NCAction> blockPolicy = new BlockPolicySource(Logger.None).GetPolicy(); IStore store = storeType.CreateStore(storePath); var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); Block <NCAction> genesisBlock = store.GetGenesisBlock <NCAction>(blockPolicy.GetHashAlgorithm); if (!(store.GetCanonicalChainId() is { } chainId)) { throw new CommandExitedException($"There is no canonical chain: {storePath}", -1); } if (!(store.IndexBlockHash(chainId, 0) is { } gHash)) { throw new CommandExitedException($"There is no genesis block: {storePath}", -1); } BlockChain <NCAction> chain = new BlockChain <NCAction>( blockPolicy, stagePolicy, store, stateStore, genesisBlock); long height = chain.Tip.Index; if (offset + limit > (int)height) { throw new CommandExitedException( $"The sum of the offset and limit is greater than the chain tip index: {height}", -1); } _console.Out.WriteLine("Block Index," + "Mining Time (sec)," + "Total Tx #," + "HAS #," + "RankingBattle #," + "Mimisbrunnr #"); var typeOfActionTypeAttribute = typeof(ActionTypeAttribute); foreach (var item in store.IterateIndexes(chain.Id, offset + 1 ?? 1, limit).Select((value, i) => new { i, value })) { var block = store.GetBlock <NCAction>(blockPolicy.GetHashAlgorithm, item.value); var previousBlock = store.GetBlock <NCAction>( blockPolicy.GetHashAlgorithm, block.PreviousHash ?? block.Hash ); var miningTime = block.Timestamp - previousBlock.Timestamp; var txCount = 0; var hackAndSlashCount = 0; var rankingBattleCount = 0; var mimisbrunnrBattleCount = 0; foreach (var tx in block.Transactions) { txCount++; foreach (var action in tx.Actions) { var actionTypeAttribute = Attribute.GetCustomAttribute(action.InnerAction.GetType(), typeOfActionTypeAttribute) as ActionTypeAttribute; if (actionTypeAttribute is null) { continue; } var typeIdentifier = actionTypeAttribute.TypeIdentifier; if (typeIdentifier.StartsWith("hack_and_slash")) { hackAndSlashCount++; } else if (typeIdentifier.StartsWith("ranking_battle")) { rankingBattleCount++; } else if (typeIdentifier.StartsWith("mimisbrunnr_battle")) { mimisbrunnrBattleCount++; } } } _console.Out.WriteLine($"{block.Index}," + $"{miningTime:s\\.ff}," + $"{txCount}," + $"{hackAndSlashCount}," + $"{rankingBattleCount}," + $"{mimisbrunnrBattleCount}"); } (store as IDisposable)?.Dispose(); }
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]); ILogger logger = new LoggerConfiguration().CreateLogger(); Libplanet.Crypto.CryptoConfig.CryptoBackend = new Secp256K1CryptoBackend <SHA256>(); var policySource = new BlockPolicySource(logger, LogEventLevel.Verbose); IBlockPolicy <NCAction> policy = policySource.GetPolicy(BlockPolicySource.DifficultyBoundDivisor + 1, 0); 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 HashDigest <SHA256> 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>(gHash); IKeyValueStore stateRootKeyValueStore = new RocksDBKeyValueStore(Path.Combine(storePath, "state_hashes")), stateKeyValueStore = new RocksDBKeyValueStore(Path.Combine(storePath, "states")); IStateStore stateStore = new TrieStateStore(stateKeyValueStore, stateRootKeyValueStore); var chain = new BlockChain <NCAction>(policy, stagePolicy, store, stateStore, genesis); long height = chain.Tip.Index; HashDigest <SHA256>[] blockHashes = limit < 0 ? chain.BlockHashes.SkipWhile((_, i) => i < height + limit).ToArray() : chain.BlockHashes.Take(limit).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; if (block.Index > 0) { blockEvals = block.Evaluate( DateTimeOffset.UtcNow, address => chain.GetState(address, block.Hash), (address, currency) => chain.GetBalance(address, currency, block.Hash) ); } else { blockEvals = block.Evaluate( DateTimeOffset.UtcNow, _ => null, ((_, currency) => new FungibleAssetValue(currency)) ); } SetStates(chain.Id, 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); }
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 async Task ValidateNextBlockTx() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( 10_000, null, null, null, null, null, null, null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet.Create(adminAddress) ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Transaction <PolymorphicAction <ActionBase> > txByStranger = Transaction <PolymorphicAction <ActionBase> > .Create( 0, new PrivateKey(), genesis.Hash, new PolymorphicAction <ActionBase>[] { } ); // New private key which is not in activated addresses list is blocked. Assert.NotNull(policy.ValidateNextBlockTx(blockChain, txByStranger)); var newActivatedPrivateKey = new PrivateKey(); var newActivatedAddress = newActivatedPrivateKey.ToAddress(); // Activate with admin account. blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction <ActionBase>[] { new AddActivatedAccount(newActivatedAddress) } ); await blockChain.MineBlock(adminPrivateKey); Transaction <PolymorphicAction <ActionBase> > txByNewActivated = Transaction <PolymorphicAction <ActionBase> > .Create( 0, newActivatedPrivateKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { } ); // Test success because the key is activated. Assert.Null(policy.ValidateNextBlockTx(blockChain, txByNewActivated)); var singleAction = new PolymorphicAction <ActionBase>[] { new DailyReward(), }; var manyActions = new PolymorphicAction <ActionBase>[] { new DailyReward(), new DailyReward(), }; Transaction <PolymorphicAction <ActionBase> > txWithSingleAction = Transaction <PolymorphicAction <ActionBase> > .Create( 0, newActivatedPrivateKey, genesis.Hash, singleAction ); Transaction <PolymorphicAction <ActionBase> > txWithManyActions = Transaction <PolymorphicAction <ActionBase> > .Create( 0, newActivatedPrivateKey, genesis.Hash, manyActions ); // Transaction with more than two actions is rejected. Assert.Null(policy.ValidateNextBlockTx(blockChain, txWithSingleAction)); Assert.NotNull(policy.ValidateNextBlockTx(blockChain, txWithManyActions)); }
public async Task ValidateNextBlockWithAuthorizedMinersState() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var minerKeys = new[] { new PrivateKey(), new PrivateKey() }; Address[] miners = minerKeys.Select(AddressExtensions.ToAddress).ToArray(); var stranger = new Address( new byte[] { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } ); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( 10000, 100, ignoreHardcodedIndicesForBackwardCompatibility: true ); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet <Address> .Empty, new AuthorizedMinersState(miners, 2, 4) ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null), new DefaultKeyValueStore(null)); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); if (policy is BlockPolicy bp) { bp.AuthorizedMinersState = new AuthorizedMinersState( (Dictionary)blockChain.GetState(AuthorizedMinersState.Address) ); } await blockChain.MineBlock(stranger); await Assert.ThrowsAsync <InvalidMinerException>(async() => { await blockChain.MineBlock(stranger); }); new Miner(blockChain, null, minerKeys[0], true).StageProofTransaction(); await blockChain.MineBlock(miners[0]); // it's okay because next block index is 3 await blockChain.MineBlock(stranger); // it isn't :( await Assert.ThrowsAsync <InvalidMinerException>(async() => { await blockChain.MineBlock(stranger); }); // the authorization block should be proved by a proof tx await Assert.ThrowsAsync <InvalidMinerException>( async() => await blockChain.MineBlock(miners[1]) ); // the proof tx should be signed by the same authorized miner var othersProof = Transaction <PolymorphicAction <ActionBase> > .Create( blockChain.GetNextTxNonce(miners[0]), minerKeys[0], blockChain.Genesis.Hash, new PolymorphicAction <ActionBase> [0] ); blockChain.StageTransaction(othersProof); await Assert.ThrowsAsync <InvalidMinerException>( async() => await blockChain.MineBlock(miners[1]) ); // the proof tx should be no-op var action = new PolymorphicAction <ActionBase>( new TransferAsset(miners[1], miners[0], new Currency("FOO", 0, miners[1]) * 1) ); var nonEmptyProof = Transaction <PolymorphicAction <ActionBase> > .Create( blockChain.GetNextTxNonce(miners[1]), minerKeys[1], blockChain.Genesis.Hash, new[] { action } ); blockChain.StageTransaction(nonEmptyProof); await Assert.ThrowsAsync <InvalidMinerException>( async() => await blockChain.MineBlock(miners[1]) ); new Miner(blockChain, null, minerKeys[1], true).StageProofTransaction(); await blockChain.MineBlock(miners[1]); // it's okay because block index exceeds limitations. await blockChain.MineBlock(stranger); }
public void ValidateNextBlockWithManyTransactionsPerSigner() { var adminPrivateKey = new PrivateKey(); var adminPublicKey = adminPrivateKey.PublicKey; var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy <PolymorphicAction <ActionBase> > policy = blockPolicySource.GetPolicy( minimumDifficulty: 10_000, hashAlgorithmTypePolicy: null, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: MaxTransactionsPerBlockPolicy .Default .Add(new SpannedSubPolicy <int>(0, null, null, 10)), maxTransactionsPerSignerPerBlockPolicy: MaxTransactionsPerSignerPerBlockPolicy .Default .Add(new SpannedSubPolicy <int>(2, null, null, 5)), authorizedMinersPolicy: null, permissionedMinersPolicy: null); IStagePolicy <PolymorphicAction <ActionBase> > stagePolicy = new VolatileStagePolicy <PolymorphicAction <ActionBase> >(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock(adminPublicKey.ToAddress(), ImmutableHashSet <Address> .Empty); using var store = new DefaultStore(null); var stateStore = new TrieStateStore(new MemoryKeyValueStore()); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( policy, stagePolicy, store, stateStore, genesis ); int nonce = 0; List <Transaction <PolymorphicAction <ActionBase> > > GenerateTransactions(int count) { var list = new List <Transaction <PolymorphicAction <ActionBase> > >(); for (int i = 0; i < count; i++) { list.Add(Transaction <PolymorphicAction <ActionBase> > .Create( nonce++, adminPrivateKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { } )); } return(list); } Assert.Equal(1, blockChain.Count); Block <PolymorphicAction <ActionBase> > block1 = new BlockContent <PolymorphicAction <ActionBase> > { Index = 1, Difficulty = policy.GetNextBlockDifficulty(blockChain), TotalDifficulty = blockChain.Tip.Difficulty + policy.GetNextBlockDifficulty(blockChain), PublicKey = adminPublicKey, PreviousHash = blockChain.Tip.Hash, Timestamp = DateTimeOffset.MinValue, Transactions = GenerateTransactions(10), }.Mine(policy.GetHashAlgorithm(1)).Evaluate(adminPrivateKey, blockChain); // Should be fine since policy hasn't kicked in yet. blockChain.Append(block1); Assert.Equal(2, blockChain.Count); Assert.True(blockChain.ContainsBlock(block1.Hash)); Block <PolymorphicAction <ActionBase> > block2 = new BlockContent <PolymorphicAction <ActionBase> > { Index = 2, Difficulty = policy.GetNextBlockDifficulty(blockChain), TotalDifficulty = blockChain.Tip.Difficulty + policy.GetNextBlockDifficulty(blockChain), PublicKey = adminPublicKey, PreviousHash = blockChain.Tip.Hash, Timestamp = DateTimeOffset.MinValue, Transactions = GenerateTransactions(10), }.Mine(policy.GetHashAlgorithm(2)).Evaluate(adminPrivateKey, blockChain); // Subpolicy kicks in. Assert.Throws <InvalidBlockTxCountPerSignerException>(() => blockChain.Append(block2)); Assert.Equal(2, blockChain.Count); Assert.False(blockChain.ContainsBlock(block2.Hash)); // Since failed, roll back nonce. nonce -= 10; // Limit should also pass. Block <PolymorphicAction <ActionBase> > block3 = new BlockContent <PolymorphicAction <ActionBase> > { Index = 2, Difficulty = policy.GetNextBlockDifficulty(blockChain), TotalDifficulty = blockChain.Tip.Difficulty + policy.GetNextBlockDifficulty(blockChain), PublicKey = adminPublicKey, PreviousHash = blockChain.Tip.Hash, Timestamp = DateTimeOffset.MinValue, Transactions = GenerateTransactions(5), }.Mine(policy.GetHashAlgorithm(2)).Evaluate(adminPrivateKey, blockChain); blockChain.Append(block3); Assert.Equal(3, blockChain.Count); Assert.True(blockChain.ContainsBlock(block3.Hash)); }
public async Task Run( [Option( "store-path", new[] { 'P' }, Description = @"The path of the blockchain store. If omitted (default) in memory version is used.")] string storePath, [Option( "store-type", new[] { 'T' }, Description = @"The type of the blockchain store. If omitted (default) in DefaultStore is used.")] string storeType, [Option( "genesis-block", new[] { 'G' }, Description = "The path of the genesis block. It should be absolute or http url.")] string genesisBlockPath, [Option("debug", new[] { 'd' }, Description = "Print logs for debugging as well.")] bool debug = false, [Option("host", new[] { 'H' }, Description = "The host address to listen.")] string host = "0.0.0.0", [Option("port", new[] { 'p' }, Description = "The port number to listen.")] int port = 5000, [Option( "block-interval", new[] { 'i' }, Description = @"An appropriate interval in milliseconds between consecutive blocks.")] int blockIntervalMilliseconds = 5000, [Option( "minimum-difficulty", new[] { 'm' }, Description = "Allowed minimum difficulty for mining blocks.")] long minimumDifficulty = 1024L, [Option( "difficulty-bound-divisor", new[] { 'D' }, Description = "A bound divisor to determine precision of block difficulties.")] int difficultyBoundDivisor = 128, [Option( "workers", new[] { 'W' }, Description = "The number of swarm workers.")] int workers = 50, [Option( "app-protocol-version", new[] { 'V' }, Description = "An app protocol version token.")] string appProtocolVersionToken = null, [Option( "mysql-server", Description = "A hostname of MySQL server.")] string mysqlServer = null, [Option( "mysql-port", Description = "A port of MySQL server.")] uint?mysqlPort = null, [Option( "mysql-username", Description = "The name of MySQL user.")] string mysqlUsername = null, [Option( "mysql-password", Description = "The password of MySQL user.")] string mysqlPassword = null, [Option( "mysql-database", Description = "The name of MySQL database to use.")] string mysqlDatabase = null, [Option( "max-transactions-per-block", Description = @"The number of maximum transactions able to be included in a block.")] int maxTransactionsPerBlock = 100, [Option( "max-block-bytes", Description = @"The number of maximum bytes size of blocks except for genesis block.")] int maxBlockBytes = 100 * 1024, [Option( "max-genesis-bytes", Description = "The number of maximum bytes size of the genesis block.")] int maxGenesisBytes = 1024 * 1024, [Option( "seed", new[] { 's' }, Description = @"Seed nodes to join to the network as a node. The format of each seed is a comma-separated triple of a peer's hexadecimal public key, host, and port number. E.g., `02ed49dbe0f2c34d9dff8335d6dd9097f7a3ef17dfb5f048382eebc7f451a50aa1,example.com,31234'. If omitted (default) explorer only the local blockchain store.")] string[] seedStrings = null, [Option( "ice-server", new[] { 'I' }, Description = "URL to ICE server (TURN/STUN) to work around NAT.")] string iceServerUrl = null ) { Options options = new Options( debug, host, port, blockIntervalMilliseconds, minimumDifficulty, difficultyBoundDivisor, workers, appProtocolVersionToken, mysqlServer, mysqlPort, mysqlUsername, mysqlPassword, mysqlDatabase, maxTransactionsPerBlock, maxBlockBytes, maxGenesisBytes, seedStrings, iceServerUrl, storePath, storeType, genesisBlockPath); var loggerConfig = new LoggerConfiguration(); loggerConfig = options.Debug ? loggerConfig.MinimumLevel.Debug() : loggerConfig.MinimumLevel.Information(); loggerConfig = loggerConfig .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .Enrich.FromLogContext() .WriteTo.Console(); Log.Logger = loggerConfig.CreateLogger(); try { IRichStore store = LoadStore(options); IStateStore stateStore = new NoOpStateStore(); IBlockPolicy <NullAction> policy = new DumbBlockPolicy(LoadBlockPolicy <NullAction>(options)); IStagePolicy <NullAction> stagePolicy = new VolatileStagePolicy <NullAction>(); var blockChain = new BlockChain <NullAction>( policy, stagePolicy, store, stateStore, options.GetGenesisBlock(policy)); Startup.PreloadedSingleton = false; Startup.BlockChainSingleton = blockChain; Startup.StoreSingleton = store; IWebHost webHost = WebHost.CreateDefaultBuilder() .UseStartup <ExplorerStartup <NullAction, Startup> >() .UseSerilog() .UseUrls($"http://{options.Host}:{options.Port}/") .Build(); Swarm <NullAction> swarm = null; if (!(options.Seeds is null)) { string aggregatedSeedStrings = options.SeedStrings.Aggregate(string.Empty, (s, s1) => s + s1); Console.Error.WriteLine( $"Seeds are {aggregatedSeedStrings}"); // TODO: Take privateKey as a CLI option // TODO: Take appProtocolVersion as a CLI option // TODO: Take host as a CLI option // TODO: Take listenPort as a CLI option if (options.IceServer is null) { Console.Error.WriteLine( "error: -s/--seed option requires -I/--ice-server as well." ); Environment.Exit(1); return; } Console.Error.WriteLine("Creating Swarm."); var privateKey = new PrivateKey(); // FIXME: The appProtocolVersion should be fixed properly. var swarmOptions = new SwarmOptions { MaxTimeout = TimeSpan.FromSeconds(10), }; swarm = new Swarm <NullAction>( blockChain, privateKey, options.AppProtocolVersionToken is string t ? AppProtocolVersion.FromToken(t) : default(AppProtocolVersion), differentAppProtocolVersionEncountered: (p, pv, lv) => true, workers: options.Workers, iceServers: new[] { options.IceServer }, options: swarmOptions ); } using (var cts = new CancellationTokenSource()) using (swarm) { Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; cts.Cancel(); }; try { await Task.WhenAll( webHost.RunAsync(cts.Token), StartSwarmAsync(swarm, options.Seeds, cts.Token) ); } catch (OperationCanceledException) { await swarm?.StopAsync(waitFor : TimeSpan.FromSeconds(1)) .ContinueWith(_ => NetMQConfig.Cleanup(false)); } } } catch (InvalidOptionValueException e) { string expectedValues = string.Join(", ", e.ExpectedValues); Console.Error.WriteLine($"Unexpected value given through '{e.OptionName}'\n" + $" given value: {e.OptionValue}\n" + $" expected values: {expectedValues}"); } }