public static Block <PolymorphicAction <ActionBase> > MineGenesisBlock( IDictionary <string, string> tableSheets, GoldDistribution[] goldDistributions, PendingActivationState[] pendingActivationStates, AdminState adminState, AuthorizedMinersState authorizedMinersState = null, IImmutableSet <Address> activatedAccounts = null, bool isActivateAdminAddress = false, IEnumerable <string> credits = null, int maximumTransactions = 100, PrivateKey privateKey = null ) { if (!tableSheets.TryGetValue(nameof(GameConfigSheet), out var csv)) { throw new KeyNotFoundException(nameof(GameConfigSheet)); } var gameConfigState = new GameConfigState(csv); var redeemCodeListSheet = new RedeemCodeListSheet(); redeemCodeListSheet.Set(tableSheets[nameof(RedeemCodeListSheet)]); if (privateKey is null) { privateKey = new PrivateKey(); } var ncg = new Currency("NCG", 2, privateKey.ToAddress()); activatedAccounts = activatedAccounts ?? ImmutableHashSet <Address> .Empty; var initialStatesAction = new InitializeStates ( rankingState: new RankingState(), shopState: new ShopState(), tableSheets: (Dictionary <string, string>)tableSheets, gameConfigState: gameConfigState, redeemCodeState: new RedeemCodeState(redeemCodeListSheet), adminAddressState: adminState, activatedAccountsState: new ActivatedAccountsState( isActivateAdminAddress ? activatedAccounts.Add(adminState.AdminAddress) : activatedAccounts), goldCurrencyState: new GoldCurrencyState(ncg), goldDistributions: goldDistributions, pendingActivationStates: pendingActivationStates, authorizedMinersState: authorizedMinersState, creditsState: credits is null ? null : new CreditsState(credits) ); var actions = new PolymorphicAction <ActionBase>[] { initialStatesAction, }; var blockAction = new BlockPolicySource(Log.Logger).GetPolicy(5000000, maximumTransactions).BlockAction; return (BlockChain <PolymorphicAction <ActionBase> > .MakeGenesisBlock( actions, privateKey : privateKey, blockAction : blockAction)); }
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); 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, 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 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 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)); }
internal static IBlockPolicy <NCAction> GetBlockPolicy(NetworkType networkType) { var source = new BlockPolicySource(Log.Logger, LogEventLevel.Debug); return(networkType switch { NetworkType.Main => source.GetPolicy(), NetworkType.Internal => source.GetInternalPolicy(), NetworkType.Test => source.GetTestPolicy(), _ => throw new ArgumentOutOfRangeException(nameof(networkType), networkType, null), });
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 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 Proof() { using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockPolicySource = new BlockPolicySource(Logger.None); var genesis = BlockChain <NCAction> .MakeGenesisBlock(HashAlgorithmType.Of <SHA256>()); var blockChain = new BlockChain <NCAction>( blockPolicySource.GetPolicy(10_000, null, null, null, null, null, null), new VolatileStagePolicy <NCAction>(), store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); var minerKey = new PrivateKey(); var miner = new Miner(blockChain, null, minerKey, false); Block <NCAction> mined = await miner.MineBlockAsync(default);
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 ValidateNextBlockWithAuthorizedMinersState() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var miners = new[] { new Address( new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } ), new Address( new byte[] { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } ), }; 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); 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, 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); }); 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); }); await blockChain.MineBlock(miners[1]); // it's okay because block index exceeds limitations. await blockChain.MineBlock(stranger); }
public void IsAllowedtoMine() { var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var authorizedMinerKey = new PrivateKey(); var permissionedMinerKey = new PrivateKey(); var someMinerKey = new PrivateKey(); var addresses = new Address[] { authorizedMinerKey.ToAddress(), permissionedMinerKey.ToAddress(), someMinerKey.ToAddress(), }; var pendingActivations = new[] { authorizedMinerKey, permissionedMinerKey, someMinerKey, }.Select(key => ActivationKey.Create(key, nonce).Item2).ToArray(); // This creates genesis with _privateKey as its miner. Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( default(Address), ImmutableHashSet <Address> .Empty, pendingActivations: pendingActivations); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockPolicySource = new BlockPolicySource(Logger.None); var policy = (BlockPolicy)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 % 2 == 0, value: new Address[] { authorizedMinerKey.ToAddress() } .ToImmutableHashSet())), permissionedMinersPolicy: PermissionedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 5, endIndex: 20, filter: index => index % 3 == 0, value: new Address[] { permissionedMinerKey.ToAddress() } .ToImmutableHashSet()))); // For genesis, any miner is allowed. Assert.All(addresses, address => Assert.True(policy.IsAllowedToMine(address, 0))); // Same goes for the next one. Assert.All(addresses, address => Assert.True(policy.IsAllowedToMine(address, 1))); // Only authorized miner should be allowed for index 2. Assert.True(policy.IsAllowedToMine(authorizedMinerKey.ToAddress(), 2)); Assert.False(policy.IsAllowedToMine(permissionedMinerKey.ToAddress(), 2)); Assert.False(policy.IsAllowedToMine(someMinerKey.ToAddress(), 2)); // Only authorized miner should be allowed for index 6. Assert.True(policy.IsAllowedToMine(authorizedMinerKey.ToAddress(), 6)); Assert.False(policy.IsAllowedToMine(permissionedMinerKey.ToAddress(), 6)); Assert.False(policy.IsAllowedToMine(someMinerKey.ToAddress(), 6)); // Any miner should be able to mine for index 7. Assert.True(policy.IsAllowedToMine(authorizedMinerKey.ToAddress(), 7)); Assert.True(policy.IsAllowedToMine(permissionedMinerKey.ToAddress(), 7)); Assert.True(policy.IsAllowedToMine(someMinerKey.ToAddress(), 7)); // Only permissioned miner should be allowed for index 9. Assert.False(policy.IsAllowedToMine(authorizedMinerKey.ToAddress(), 9)); Assert.True(policy.IsAllowedToMine(permissionedMinerKey.ToAddress(), 9)); Assert.False(policy.IsAllowedToMine(someMinerKey.ToAddress(), 9)); // Only permissioned miner should be allowed for index 12. Assert.False(policy.IsAllowedToMine(authorizedMinerKey.ToAddress(), 12)); Assert.True(policy.IsAllowedToMine(permissionedMinerKey.ToAddress(), 12)); Assert.False(policy.IsAllowedToMine(someMinerKey.ToAddress(), 12)); // Any miner should be able to mine 24. Assert.True(policy.IsAllowedToMine(authorizedMinerKey.ToAddress(), 24)); Assert.True(policy.IsAllowedToMine(permissionedMinerKey.ToAddress(), 24)); Assert.True(policy.IsAllowedToMine(someMinerKey.ToAddress(), 24)); }
public async Task PermissionedBlockPolicy() { // This creates genesis with _privateKey as its miner. var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var permissionedMinerKey = new PrivateKey(); var nonPermissionedMinerKey = new PrivateKey(); var pendingActivations = new[] { permissionedMinerKey, nonPermissionedMinerKey, }.Select(key => ActivationKey.Create(key, nonce).Item2).ToArray(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( default(Address), ImmutableHashSet <Address> .Empty, pendingActivations: pendingActivations); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockPolicySource = new BlockPolicySource(Logger.None); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( blockPolicySource.GetPolicy( minimumDifficulty: 10_000, hashAlgorithmTypePolicy: null, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: null, maxTransactionsPerSignerPerBlockPolicy: null, authorizedMinersPolicy: null, permissionedMinersPolicy: PermissionedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 1, endIndex: null, filter: null, value: new Address[] { permissionedMinerKey.ToAddress() } .ToImmutableHashSet()))), new VolatileStagePolicy <PolymorphicAction <ActionBase> >(), store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); // Old proof mining is still allowed. blockChain.StageTransaction(Transaction <PolymorphicAction <ActionBase> > .Create( 0, permissionedMinerKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { } )); await blockChain.MineBlock(permissionedMinerKey); // Bad proof can also be mined. blockChain.StageTransaction(Transaction <PolymorphicAction <ActionBase> > .Create( 0, nonPermissionedMinerKey, genesis.Hash, new PolymorphicAction <ActionBase>[] { } )); await blockChain.MineBlock(permissionedMinerKey); await blockChain.MineBlock(permissionedMinerKey); // Error, it isn't permissioned miner. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(nonPermissionedMinerKey)); }
public NineChroniclesNodeService( LibplanetNodeServiceProperties <NineChroniclesActionType> properties, RpcNodeServiceProperties?rpcNodeServiceProperties, Progress <PreloadState> preloadProgress = null, bool ignoreBootstrapFailure = false, bool strictRendering = false, bool isDev = false, int blockInterval = 10000, int reorgInterval = 0 ) { Properties = properties; RpcProperties = rpcNodeServiceProperties; try { Libplanet.Crypto.CryptoConfig.CryptoBackend = new Secp256K1CryptoBackend <SHA256>(); Log.Debug("Secp256K1CryptoBackend initialized."); } catch (Exception e) { Log.Error("Secp256K1CryptoBackend initialize failed. Use default backend. {e}", e); } var blockPolicySource = new BlockPolicySource(Log.Logger, LogEventLevel.Debug); // BlockPolicy shared through Lib9c. IBlockPolicy <PolymorphicAction <ActionBase> > blockPolicy = null; // Policies for dev mode. IBlockPolicy <PolymorphicAction <ActionBase> > easyPolicy = null; IBlockPolicy <PolymorphicAction <ActionBase> > hardPolicy = null; if (isDev) { easyPolicy = new ReorgPolicy(new RewardGold(), 1); hardPolicy = new ReorgPolicy(new RewardGold(), 2); } else { blockPolicy = blockPolicySource.GetPolicy(properties.MinimumDifficulty, properties.MaximumTransactions); } BlockRenderer = blockPolicySource.BlockRenderer; ActionRenderer = blockPolicySource.ActionRenderer; ExceptionRenderer = new ExceptionRenderer(); NodeStatusRenderer = new NodeStatusRenderer(); var renderers = new List <IRenderer <NineChroniclesActionType> >(); var strictRenderer = new StrictRenderer(onError: exc => ExceptionRenderer.RenderException( RPCException.InvalidRenderException, exc.Message.Split("\n")[0] ) ); if (Properties.Render) { renderers.Add(blockPolicySource.BlockRenderer); renderers.Add(blockPolicySource.LoggedActionRenderer); } else { renderers.Add(blockPolicySource.LoggedBlockRenderer); } if (strictRendering) { Log.Debug( $"Strict rendering is on. Add {nameof(StrictRenderer)}."); renderers.Add(strictRenderer); } async Task minerLoopAction( BlockChain <NineChroniclesActionType> chain, Swarm <NineChroniclesActionType> swarm, PrivateKey privateKey, CancellationToken cancellationToken) { var miner = new Miner(chain, swarm, privateKey); Log.Debug("Miner called."); while (!cancellationToken.IsCancellationRequested) { try { if (swarm.Running) { Log.Debug("Start mining."); await miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken); } else { await Task.Delay(1000, cancellationToken); } } catch (Exception ex) { Log.Error(ex, "Exception occurred."); } } } async Task devMinerLoopAction( Swarm <NineChroniclesActionType> mainSwarm, Swarm <NineChroniclesActionType> subSwarm, PrivateKey privateKey, CancellationToken cancellationToken) { var miner = new ReorgMiner(mainSwarm, subSwarm, privateKey, reorgInterval); Log.Debug("Miner called."); while (!cancellationToken.IsCancellationRequested) { try { if (mainSwarm.Running) { Log.Debug("Start mining."); await miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken); await Task.Delay(blockInterval, cancellationToken); } else { await Task.Delay(1000, cancellationToken); } } catch (Exception ex) { Log.Error(ex, "Exception occurred."); } } } if (isDev) { NodeService = new DevLibplanetNodeService <NineChroniclesActionType>( Properties, easyPolicy, hardPolicy, renderers, devMinerLoopAction, preloadProgress, (code, msg) => { ExceptionRenderer.RenderException(code, msg); Log.Error(msg); }, isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); }, ignoreBootstrapFailure ); } else { NodeService = new LibplanetNodeService <NineChroniclesActionType>( Properties, blockPolicy, renderers, minerLoopAction, preloadProgress, (code, msg) => { ExceptionRenderer.RenderException(code, msg); Log.Error(msg); }, isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); }, ignoreBootstrapFailure ); } strictRenderer.BlockChain = NodeService?.BlockChain ?? throw new Exception("BlockChain is null."); if (NodeService?.BlockChain?.GetState(AuthorizedMinersState.Address) is Dictionary ams && blockPolicy is BlockPolicy bp) { bp.AuthorizedMinersState = new AuthorizedMinersState(ams); } }
public NineChroniclesNodeService( PrivateKey?minerPrivateKey, LibplanetNodeServiceProperties <NCAction> properties, IBlockPolicy <NCAction> blockPolicy, NetworkType networkType, Progress <PreloadState>?preloadProgress = null, bool ignoreBootstrapFailure = false, bool ignorePreloadFailure = false, bool strictRendering = false, bool authorizedMiner = false, bool isDev = false, int blockInterval = 10000, int reorgInterval = 0, TimeSpan txLifeTime = default, int minerCount = 1, int txQuotaPerSigner = 10 ) { MinerPrivateKey = minerPrivateKey; Properties = properties; LogEventLevel logLevel = LogEventLevel.Debug; var blockPolicySource = new BlockPolicySource(Log.Logger, logLevel); // Policies for dev mode. IBlockPolicy <NCAction>?easyPolicy = null; IBlockPolicy <NCAction>?hardPolicy = null; IStagePolicy <NCAction> stagePolicy = new StagePolicy(txLifeTime, txQuotaPerSigner); if (isDev) { easyPolicy = new ReorgPolicy(new RewardGold(), 1); hardPolicy = new ReorgPolicy(new RewardGold(), 2); } BlockRenderer = blockPolicySource.BlockRenderer; ActionRenderer = blockPolicySource.ActionRenderer; ExceptionRenderer = new ExceptionRenderer(); NodeStatusRenderer = new NodeStatusRenderer(); var renderers = new List <IRenderer <NCAction> >(); var strictRenderer = new StrictRenderer(onError: exc => ExceptionRenderer.RenderException( RPCException.InvalidRenderException, exc.Message.Split("\n")[0] ) ); if (Properties.Render) { renderers.Add(blockPolicySource.BlockRenderer); renderers.Add(blockPolicySource.LoggedActionRenderer); } else if (Properties.LogActionRenders) { renderers.Add(blockPolicySource.BlockRenderer); // The following "nullRenderer" does nothing. It's just for filling // the LoggedActionRenderer<T>() constructor's parameter: IActionRenderer <NCAction> nullRenderer = new AnonymousActionRenderer <NCAction>(); renderers.Add( new LoggedActionRenderer <NCAction>( nullRenderer, Log.Logger, logLevel ) ); } else { renderers.Add(blockPolicySource.LoggedBlockRenderer); } if (strictRendering) { Log.Debug( $"Strict rendering is on. Add {nameof(StrictRenderer)}."); renderers.Add(strictRenderer); } async Task minerLoopAction( BlockChain <NCAction> chain, Swarm <NCAction> swarm, PrivateKey privateKey, CancellationToken cancellationToken) { var miner = new Miner(chain, swarm, privateKey, authorizedMiner); Log.Debug("Miner called."); while (!cancellationToken.IsCancellationRequested) { try { long nextBlockIndex = chain.Tip.Index + 1; if (swarm.Running) { Log.Debug("Start mining."); if (chain.Policy is BlockPolicy bp) { if (bp.IsAllowedToMine(privateKey.ToAddress(), chain.Count)) { IEnumerable <Task <Block <NCAction> > > miners = Enumerable .Range(0, minerCount) .Select(_ => miner.MineBlockAsync(cancellationToken)); await Task.WhenAll(miners); } else { Log.Debug( "Miner {MinerAddress} is not allowed to mine a block with index {Index} " + "under current policy.", privateKey.ToAddress(), chain.Count); await Task.Delay(1000, cancellationToken); } } else { Log.Error( "No suitable policy was found for chain {ChainId}.", chain.Id); await Task.Delay(1000, cancellationToken); } } else { await Task.Delay(1000, cancellationToken); } } catch (Exception ex) { Log.Error(ex, "Exception occurred."); } } } async Task devMinerLoopAction( Swarm <NCAction> mainSwarm, Swarm <NCAction> subSwarm, PrivateKey privateKey, CancellationToken cancellationToken) { var miner = new ReorgMiner(mainSwarm, subSwarm, privateKey, reorgInterval); Log.Debug("Miner called."); while (!cancellationToken.IsCancellationRequested) { try { if (mainSwarm.Running) { Log.Debug("Start mining."); await miner.MineBlockAsync(cancellationToken); await Task.Delay(blockInterval, cancellationToken); } else { await Task.Delay(1000, cancellationToken); } } catch (Exception ex) { Log.Error(ex, "Exception occurred."); } } } if (isDev) { NodeService = new DevLibplanetNodeService <NCAction>( Properties, easyPolicy, hardPolicy, stagePolicy, renderers, devMinerLoopAction, preloadProgress, (code, msg) => { ExceptionRenderer.RenderException(code, msg); Log.Error(msg); }, isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); }, ignoreBootstrapFailure ); } else { NodeService = new LibplanetNodeService <NCAction>( Properties, blockPolicy, stagePolicy, renderers, minerLoopAction, preloadProgress, (code, msg) => { ExceptionRenderer.RenderException(code, msg); Log.Error(msg); }, isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); }, ignoreBootstrapFailure, ignorePreloadFailure ); } strictRenderer.BlockChain = NodeService.BlockChain ?? throw new Exception("BlockChain is null."); }
public async Task DoesTransactionFollowsPolicy() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var activatedPrivateKey = new PrivateKey(); var activatedAddress = activatedPrivateKey.ToAddress(); var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy<PolymorphicAction<ActionBase>> policy = blockPolicySource.GetPolicy(10000, 100); Block<PolymorphicAction<ActionBase>> genesis = MakeGenesisBlock( adminAddress, ImmutableHashSet.Create(activatedAddress).Add(adminAddress) ); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null), new DefaultKeyValueStore(null)); var blockChain = new BlockChain<PolymorphicAction<ActionBase>>( policy, 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.False(policy.DoesTransactionFollowsPolicy(txByStranger, blockChain)); var newActivatedPrivateKey = new PrivateKey(); var newActivatedAddress = newActivatedPrivateKey.ToAddress(); // Activate with admin account. Transaction<PolymorphicAction<ActionBase>> invitationTx = blockChain.MakeTransaction( adminPrivateKey, new PolymorphicAction<ActionBase>[] { new AddActivatedAccount(newActivatedAddress) } ); blockChain.StageTransaction(invitationTx); await blockChain.MineBlock(adminAddress); Transaction<PolymorphicAction<ActionBase>> txByNewActivated = Transaction<PolymorphicAction<ActionBase>>.Create( 0, newActivatedPrivateKey, genesis.Hash, new PolymorphicAction<ActionBase>[] { } ); // Test success because the key is activated. Assert.True(policy.DoesTransactionFollowsPolicy(txByNewActivated, blockChain)); var singleAction = new PolymorphicAction<ActionBase>[] { new RewardGold(), }; var manyActions = new PolymorphicAction<ActionBase>[] { new RewardGold(), new RewardGold(), }; Transaction<PolymorphicAction<ActionBase>> txWithSingleAction = Transaction<PolymorphicAction<ActionBase>>.Create( 0, activatedPrivateKey, genesis.Hash, singleAction ); Transaction<PolymorphicAction<ActionBase>> txWithManyActions = Transaction<PolymorphicAction<ActionBase>>.Create( 0, activatedPrivateKey, genesis.Hash, manyActions ); // Transaction with more than two actions is rejected. Assert.True(policy.DoesTransactionFollowsPolicy(txWithSingleAction, blockChain)); Assert.False(policy.DoesTransactionFollowsPolicy(txWithManyActions, 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); 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, 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)); }
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); }
public async Task GetNextBlockDifficultyWithAuthorizedMinersState() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var miner = new PrivateKey().ToAddress(); var miners = new[] { miner }; var blockPolicySource = new BlockPolicySource(Logger.None); IBlockPolicy<PolymorphicAction<ActionBase>> policy = blockPolicySource.GetPolicy(4096, 100); 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, store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); 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)); 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)); 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)); 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 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 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 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(); }
public async Task MixedMiningPolicy() { var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var authorizedMinerKey = new PrivateKey(); var permissionedMinerKey = new PrivateKey(); var someMinerKey = new PrivateKey(); var addresses = new Address[] { authorizedMinerKey.ToAddress(), permissionedMinerKey.ToAddress(), someMinerKey.ToAddress(), }; var pendingActivations = new[] { authorizedMinerKey, permissionedMinerKey, someMinerKey, }.Select(key => ActivationKey.Create(key, nonce).Item2).ToArray(); var action = new TransferAsset( new PrivateKey().ToAddress(), new PrivateKey().ToAddress(), new FungibleAssetValue(_currency, 0, 0)); // This creates genesis with _privateKey as its miner. Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( default(Address), ImmutableHashSet <Address> .Empty, pendingActivations: pendingActivations); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockPolicySource = new BlockPolicySource(Logger.None); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( 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: 6, filter: index => index % 2 == 0, value: new Address[] { authorizedMinerKey.ToAddress() } .ToImmutableHashSet())), permissionedMinersPolicy: PermissionedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 2, endIndex: 10, filter: index => index % 3 == 0, value: new Address[] { permissionedMinerKey.ToAddress() } .ToImmutableHashSet()))), new VolatileStagePolicy <PolymorphicAction <ActionBase> >(), store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Transaction <PolymorphicAction <ActionBase> > proof; // Index 1: Anyone can mine. await blockChain.MineBlock(someMinerKey); // Index 2: Only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(permissionedMinerKey)); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); await blockChain.MineBlock(authorizedMinerKey); // Index 3: Only permissioned miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(authorizedMinerKey)); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); await blockChain.MineBlock(permissionedMinerKey); // Index 4: Only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(permissionedMinerKey)); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); await blockChain.MineBlock(authorizedMinerKey); // Index 5: Anyone can mine again. await blockChain.MineBlock(someMinerKey); // Index 6: In case both authorized mining and permissioned mining apply, // only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(permissionedMinerKey)); await blockChain.MineBlock(authorizedMinerKey); // Index 7, 8, 9: Check authorized mining ended. await blockChain.MineBlock(someMinerKey); await blockChain.MineBlock(someMinerKey); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); proof = blockChain.MakeTransaction( permissionedMinerKey, new PolymorphicAction <ActionBase>[] { action }); await blockChain.MineBlock(permissionedMinerKey); // Index 10, 11, 12: Check permissioned mining ended. await blockChain.MineBlock(someMinerKey); await blockChain.MineBlock(someMinerKey); await blockChain.MineBlock(someMinerKey); // Index 13, 14: Check authorized miner and permissioned miner can also mine // when policy is allowed for all miners. await blockChain.MineBlock(authorizedMinerKey); await blockChain.MineBlock(permissionedMinerKey); }
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 NineChroniclesNodeService( PrivateKey?minerPrivateKey, LibplanetNodeServiceProperties <NCAction> properties, Progress <PreloadState>?preloadProgress = null, bool ignoreBootstrapFailure = false, bool ignorePreloadFailure = false, bool strictRendering = false, bool authorizedMiner = false, bool isDev = false, int blockInterval = 10000, int reorgInterval = 0, TimeSpan txLifeTime = default, int minerCount = 1 ) { MinerPrivateKey = minerPrivateKey; Properties = properties; LogEventLevel logLevel = LogEventLevel.Debug; var blockPolicySource = new BlockPolicySource(Log.Logger, logLevel); // BlockPolicy shared through Lib9c. IBlockPolicy <NCAction>?blockPolicy = null; // Policies for dev mode. IBlockPolicy <NCAction>?easyPolicy = null; IBlockPolicy <NCAction>?hardPolicy = null; IStagePolicy <NCAction> stagePolicy = txLifeTime == default ? new VolatileStagePolicy <NCAction>() : new VolatileStagePolicy <NCAction>(txLifeTime); if (isDev) { easyPolicy = new ReorgPolicy(new RewardGold(), 1); hardPolicy = new ReorgPolicy(new RewardGold(), 2); } else { blockPolicy = blockPolicySource.GetPolicy(properties.MinimumDifficulty, properties.MaximumTransactions); } BlockRenderer = blockPolicySource.BlockRenderer; ActionRenderer = blockPolicySource.ActionRenderer; ExceptionRenderer = new ExceptionRenderer(); NodeStatusRenderer = new NodeStatusRenderer(); var renderers = new List <IRenderer <NCAction> >(); var strictRenderer = new StrictRenderer(onError: exc => ExceptionRenderer.RenderException( RPCException.InvalidRenderException, exc.Message.Split("\n")[0] ) ); if (Properties.Render) { renderers.Add(blockPolicySource.BlockRenderer); renderers.Add(blockPolicySource.LoggedActionRenderer); } else if (Properties.LogActionRenders) { renderers.Add(blockPolicySource.BlockRenderer); // The following "nullRenderer" does nothing. It's just for filling // the LoggedActionRenderer<T>() constructor's parameter: IActionRenderer <NCAction> nullRenderer = new AnonymousActionRenderer <NCAction>(); renderers.Add( new LoggedActionRenderer <NCAction>( nullRenderer, Log.Logger, logLevel ) ); } else { renderers.Add(blockPolicySource.LoggedBlockRenderer); } if (strictRendering) { Log.Debug( $"Strict rendering is on. Add {nameof(StrictRenderer)}."); renderers.Add(strictRenderer); } async Task minerLoopAction( BlockChain <NCAction> chain, Swarm <NCAction> swarm, PrivateKey privateKey, CancellationToken cancellationToken) { var miner = new Miner(chain, swarm, privateKey, authorizedMiner); Log.Debug("Miner called."); while (!cancellationToken.IsCancellationRequested) { try { long nextBlockIndex = chain.Tip.Index + 1; bool authBlock = blockPolicy is BlockPolicy bp // Copied from https://git.io/JLxNd && nextBlockIndex > 0 && nextBlockIndex <= bp.AuthorizedMinersState?.ValidUntil && nextBlockIndex % bp.AuthorizedMinersState?.Interval == 0; if (swarm.Running && ((authorizedMiner && authBlock) || (!authorizedMiner && !authBlock))) { Log.Debug("Start mining."); IEnumerable <Task <Block <NCAction> > > miners = Enumerable .Range(0, minerCount) .Select(_ => miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken)); await Task.WhenAll(miners); } else { await Task.Delay(1000, cancellationToken); } } catch (Exception ex) { Log.Error(ex, "Exception occurred."); } } } async Task devMinerLoopAction( Swarm <NCAction> mainSwarm, Swarm <NCAction> subSwarm, PrivateKey privateKey, CancellationToken cancellationToken) { var miner = new ReorgMiner(mainSwarm, subSwarm, privateKey, reorgInterval); Log.Debug("Miner called."); while (!cancellationToken.IsCancellationRequested) { try { if (mainSwarm.Running) { Log.Debug("Start mining."); await miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken); await Task.Delay(blockInterval, cancellationToken); } else { await Task.Delay(1000, cancellationToken); } } catch (Exception ex) { Log.Error(ex, "Exception occurred."); } } } if (isDev) { NodeService = new DevLibplanetNodeService <NCAction>( Properties, easyPolicy, hardPolicy, stagePolicy, renderers, devMinerLoopAction, preloadProgress, (code, msg) => { ExceptionRenderer.RenderException(code, msg); Log.Error(msg); }, isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); }, ignoreBootstrapFailure ); } else { NodeService = new LibplanetNodeService <NCAction>( Properties, blockPolicy, stagePolicy, renderers, minerLoopAction, preloadProgress, (code, msg) => { ExceptionRenderer.RenderException(code, msg); Log.Error(msg); }, isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); }, ignoreBootstrapFailure, ignorePreloadFailure ); } strictRenderer.BlockChain = NodeService.BlockChain ?? throw new Exception("BlockChain is null."); if (NodeService.BlockChain?.GetState(AuthorizedMinersState.Address) is Dictionary ams && blockPolicy is BlockPolicy bp) { bp.AuthorizedMinersState = new AuthorizedMinersState(ams); } if (authorizedMiner && blockPolicy is BlockPolicy { AuthorizedMinersState : null })
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); }