public StandaloneMutation( StandaloneContext standaloneContext, NineChroniclesNodeService nodeService, IConfiguration configuration ) { if (configuration[GraphQLService.SecretTokenKey] is { })
public RenderSubscriber( NineChroniclesNodeService nodeService, MySqlStore mySqlStore ) { _blockRenderer = nodeService.BlockRenderer; _actionRenderer = nodeService.ActionRenderer; _exceptionRenderer = nodeService.ExceptionRenderer; _nodeStatusRenderer = nodeService.NodeStatusRenderer; MySqlStore = mySqlStore; }
public async Task TransferGold() { NineChroniclesNodeService service = StandaloneContextFx.NineChroniclesNodeService !; Currency goldCurrency = new GoldCurrencyState( (Dictionary)BlockChain.GetState(GoldCurrencyState.Address) ).Currency; Address senderAddress = service.MinerPrivateKey !.ToAddress(); var store = service.Store; await BlockChain.MineBlock(service.MinerPrivateKey); await BlockChain.MineBlock(service.MinerPrivateKey); // 10 + 10 (mining rewards) Assert.Equal( 20 * goldCurrency, BlockChain.GetBalance(senderAddress, goldCurrency) ); var recipientKey = new PrivateKey(); Address recipient = recipientKey.ToAddress(); var query = $"mutation {{ transferGold(recipient: \"{recipient}\", amount: \"17.5\") }}"; ExecutionResult result = await ExecuteQueryAsync(query); var stagedTxIds = BlockChain.GetStagedTransactionIds().ToImmutableList(); Assert.Single(stagedTxIds); var expectedResult = new Dictionary <string, object> { ["transferGold"] = stagedTxIds.Single().ToString(), }; Assert.Null(result.Errors); Assert.Equal(expectedResult, result.Data); await BlockChain.MineBlock(recipientKey); // 10 + 10 - 17.5(transfer) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "2.5"), BlockChain.GetBalance(senderAddress, goldCurrency) ); // 0 + 17.5(transfer) + 10(mining reward) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "27.5"), BlockChain.GetBalance(recipient, goldCurrency) ); }
public async Task ActivateAccount() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var activateAccounts = new[] { adminAddress }.ToImmutableHashSet(); Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock(adminAddress, new Currency("NCG", 2, minters: null), activateAccounts); NineChroniclesNodeService service = ServiceBuilder.CreateNineChroniclesNodeService(genesis); StandaloneContextFx.NineChroniclesNodeService = service; StandaloneContextFx.BlockChain = service.Swarm.BlockChain; var blockChain = StandaloneContextFx.BlockChain; var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var privateKey = new PrivateKey(); (ActivationKey activationKey, PendingActivationState pendingActivation) = ActivationKey.Create(privateKey, nonce); PolymorphicAction <ActionBase> action = new CreatePendingActivation(pendingActivation); blockChain.MakeTransaction(adminPrivateKey, new[] { action }); await blockChain.MineBlock(adminAddress); var encodedActivationKey = activationKey.Encode(); var queryResult = await ExecuteQueryAsync( $"mutation {{ activationStatus {{ activateAccount(encodedActivationKey: \"{encodedActivationKey}\") }} }}"); await blockChain.MineBlock(adminAddress); var result = (bool)queryResult.Data .As <Dictionary <string, object> >()["activationStatus"] .As <Dictionary <string, object> >()["activateAccount"]; Assert.True(result); var state = (Bencodex.Types.Dictionary)blockChain.GetState( ActivatedAccountsState.Address); var activatedAccountsState = new ActivatedAccountsState(state); Address userAddress = service.PrivateKey.ToAddress(); Assert.True(activatedAccountsState.Accounts.Contains(userAddress)); }
private NineChroniclesNodeService MakeMineChroniclesNodeService(PrivateKey privateKey) { var goldCurrency = new Currency("NCG", 2, minter: null); int minimumDifficulty = 4096; var blockAction = NineChroniclesNodeService.GetBlockPolicy(minimumDifficulty, new LibplanetNodeServiceProperties <PolymorphicAction <ActionBase> >().MaximumTransactions).BlockAction; Block <PolymorphicAction <ActionBase> > genesis = BlockChain <PolymorphicAction <ActionBase> > .MakeGenesisBlock( new PolymorphicAction <ActionBase>[] { new InitializeStates( rankingState: new RankingState(), shopState: new ShopState(), gameConfigState: new GameConfigState(_sheets[nameof(GameConfigSheet)]), redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty .Add("address", RedeemCodeState.Address.Serialize()) .Add("map", Bencodex.Types.Dictionary.Empty) ), adminAddressState: new AdminState(default, 0),
private NineChroniclesNodeService MakeMineChroniclesNodeService(PrivateKey privateKey) { var goldCurrency = new Currency("NCG", 2, minter: null); var blockPolicy = NineChroniclesNodeService.GetTestBlockPolicy(); Block <PolymorphicAction <ActionBase> > genesis = BlockChain <PolymorphicAction <ActionBase> > .MakeGenesisBlock( HashAlgorithmType.Of <SHA256>(), new PolymorphicAction <ActionBase>[] { new InitializeStates( rankingState: new RankingState(), shopState: new ShopState(), gameConfigState: new GameConfigState(_sheets[nameof(GameConfigSheet)]), redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty .Add("address", RedeemCodeState.Address.Serialize()) .Add("map", Bencodex.Types.Dictionary.Empty) ), adminAddressState: new AdminState(default, 0),
public ActivationStatusMutation(NineChroniclesNodeService service) { Field <NonNullGraphType <BooleanGraphType> >("activateAccount", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "encodedActivationKey", }), resolve: context => { try { string encodedActivationKey = context.GetArgument <string>("encodedActivationKey"); // FIXME: Private key may not exists at this moment. if (!(service.MinerPrivateKey is { } privateKey)) { throw new InvalidOperationException($"{nameof(privateKey)} is null."); } ActivationKey activationKey = ActivationKey.Decode(encodedActivationKey); if (!(service.Swarm?.BlockChain is { } blockChain)) { throw new InvalidOperationException($"{nameof(blockChain)} is null."); } IValue state = blockChain.GetState(activationKey.PendingAddress); if (!(state is Bencodex.Types.Dictionary asDict)) { context.Errors.Add(new ExecutionError("The given key was already expired.")); return(false); } var pendingActivationState = new PendingActivationState(asDict); ActivateAccount action = activationKey.CreateActivateAccount( pendingActivationState.Nonce); var actions = new NCAction[] { action }; blockChain.MakeTransaction(privateKey, actions); }
public async Task ActivationStatus(bool existsActivatedAccounts) { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var activatedAccounts = ImmutableHashSet <Address> .Empty; if (existsActivatedAccounts) { activatedAccounts = new[] { adminAddress }.ToImmutableHashSet(); } Block <PolymorphicAction <ActionBase> > genesis = BlockChain <PolymorphicAction <ActionBase> > .MakeGenesisBlock( new PolymorphicAction <ActionBase>[] { new InitializeStates( rankingState: new RankingState(), shopState: new ShopState(), gameConfigState: new GameConfigState(), redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty .Add("address", RedeemCodeState.Address.Serialize()) .Add("map", Bencodex.Types.Dictionary.Empty) ), adminAddressState: new AdminState(adminAddress, 1500000), activatedAccountsState: new ActivatedAccountsState(activatedAccounts), goldCurrencyState: new GoldCurrencyState(new Currency("NCG", 2, minter: null)), goldDistributions: new GoldDistribution[0], tableSheets: _sheets, pendingActivationStates: new PendingActivationState[] { } ), } ); var apvPrivateKey = new PrivateKey(); var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); var userPrivateKey = new PrivateKey(); var properties = new LibplanetNodeServiceProperties <PolymorphicAction <ActionBase> > { Host = System.Net.IPAddress.Loopback.ToString(), AppProtocolVersion = apv, GenesisBlock = genesis, StorePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), StoreStatesCacheSize = 2, SwarmPrivateKey = new PrivateKey(), Port = null, MinimumDifficulty = 4096, NoMiner = true, Render = false, Peers = ImmutableHashSet <Peer> .Empty, TrustedAppProtocolVersionSigners = null, StaticPeers = ImmutableHashSet <Peer> .Empty }; var service = new NineChroniclesNodeService(userPrivateKey, properties, null); StandaloneContextFx.NineChroniclesNodeService = service; StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; var blockChain = StandaloneContextFx.BlockChain !; var queryResult = await ExecuteQueryAsync("query { activationStatus { activated } }"); var result = (bool)queryResult.Data .As <Dictionary <string, object> >()["activationStatus"] .As <Dictionary <string, object> >()["activated"]; // ActivatedAccounts가 비어있을때는 true이고 하나라도 있을경우 false Assert.Equal(!existsActivatedAccounts, result); var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var privateKey = new PrivateKey(); (ActivationKey activationKey, PendingActivationState pendingActivation) = ActivationKey.Create(privateKey, nonce); PolymorphicAction <ActionBase> action = new CreatePendingActivation(pendingActivation); blockChain.MakeTransaction(adminPrivateKey, new[] { action }); await blockChain.MineBlock(adminAddress); action = activationKey.CreateActivateAccount(nonce); blockChain.MakeTransaction(userPrivateKey, new[] { action }); await blockChain.MineBlock(adminAddress); queryResult = await ExecuteQueryAsync("query { activationStatus { activated } }"); result = (bool)queryResult.Data .As <Dictionary <string, object> >()["activationStatus"] .As <Dictionary <string, object> >()["activated"]; // ActivatedAccounts에 Address가 추가 되었기 때문에 true Assert.True(result); }
public ActionMutation(NineChroniclesNodeService service) { Field <NonNullGraphType <TxIdType> >("createAvatar", description: "Create new avatar.", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "avatarName", Description = "Avatar name." }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "avatarIndex", Description = "The index of character slot. 0 ~ 2" }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "hairIndex", Description = "The index of character hair color. 0 ~ 8" }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "lensIndex", Description = "The index of character eye color. 0 ~ 8" }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "earIndex", Description = "The index of character ear color. 0 ~ 8" }, new QueryArgument <NonNullGraphType <IntGraphType> > { Name = "tailIndex", Description = "The index of character tail color. 0 ~ 8" } ), resolve: context => { try { if (!(service.MinerPrivateKey is { } privateKey)) { throw new InvalidOperationException($"{nameof(service.MinerPrivateKey)} is null."); } if (!(service.Swarm?.BlockChain is { } blockChain)) { throw new InvalidOperationException($"{nameof(service.Swarm.BlockChain)} is null."); } var avatarName = context.GetArgument <string>("avatarName"); var avatarIndex = context.GetArgument <int>("avatarIndex"); var hairIndex = context.GetArgument <int>("hairIndex"); var lensIndex = context.GetArgument <int>("lensIndex"); var earIndex = context.GetArgument <int>("earIndex"); var tailIndex = context.GetArgument <int>("tailIndex"); var action = new CreateAvatar { index = avatarIndex, hair = hairIndex, lens = lensIndex, ear = earIndex, tail = tailIndex, name = avatarName, }; var actions = new NCAction[] { action }; Transaction <NCAction> tx = blockChain.MakeTransaction(privateKey, actions); return(tx.Id); }
public async Task Run( bool noMiner = false, [Option("app-protocol-version", new[] { 'V' }, Description = "App protocol version token")] string appProtocolVersionToken = null, [Option('G')] string genesisBlockPath = null, [Option('H')] string host = null, [Option('P')] ushort?port = null, [Option('D')] int minimumDifficulty = 5000000, [Option("private-key")] string privateKeyString = null, string storeType = null, string storePath = null, [Option("ice-server", new [] { 'I', })] string[] iceServerStrings = null, [Option("peer")] string[] peerStrings = null, [Option("no-trusted-state-validators")] bool noTrustedStateValidators = false, [Option("trusted-app-protocol-version-signer", new[] { 'T' }, Description = "Trustworthy signers who claim new app protocol versions")] string[] trustedAppProtocolVersionSigners = null, bool rpcServer = false, string rpcListenHost = "0.0.0.0", int?rpcListenPort = null, [Option("graphql-server")] bool graphQLServer = false, [Option("graphql-host")] string graphQLHost = "0.0.0.0", [Option("graphql-port")] int?graphQLPort = null, [Option("libplanet-node")] bool libplanetNode = false ) { #if SENTRY || !DEBUG try { #endif // Setup logger. var loggerConf = new LoggerConfiguration() .WriteTo.Console() .MinimumLevel.Debug(); #if SENTRY || !DEBUG loggerConf = loggerConf .WriteTo.Sentry(o => { o.InitializeSdk = false; }); #endif Log.Logger = loggerConf.CreateLogger(); if (!graphQLServer && !libplanetNode) { throw new CommandExitedException( "Either --graphql-server or --libplanet-node must be present.", -1 ); } var tasks = new List <Task>(); try { IHostBuilder graphQLHostBuilder = Host.CreateDefaultBuilder(); var standaloneContext = new StandaloneContext { KeyStore = Web3KeyStore.DefaultKeyStore, }; if (graphQLServer) { var graphQLNodeServiceProperties = new GraphQLNodeServiceProperties { GraphQLServer = graphQLServer, GraphQLListenHost = graphQLHost, GraphQLListenPort = graphQLPort, }; var graphQLService = new GraphQLService(graphQLNodeServiceProperties); graphQLHostBuilder = graphQLService.Configure(graphQLHostBuilder, standaloneContext); tasks.Add(graphQLHostBuilder.RunConsoleAsync(Context.CancellationToken)); await WaitForGraphQLService(graphQLNodeServiceProperties, Context.CancellationToken); } if (appProtocolVersionToken is null) { throw new CommandExitedException( "--app-protocol-version must be present.", -1 ); } if (genesisBlockPath is null) { throw new CommandExitedException( "--genesis-block-path must be present.", -1 ); } RpcNodeServiceProperties?rpcProperties = null; var properties = NineChroniclesNodeServiceProperties .GenerateLibplanetNodeServiceProperties( appProtocolVersionToken, genesisBlockPath, host, port, minimumDifficulty, privateKeyString, storeType, storePath, 100, iceServerStrings, peerStrings, noTrustedStateValidators, trustedAppProtocolVersionSigners, noMiner); if (rpcServer) { rpcProperties = NineChroniclesNodeServiceProperties .GenerateRpcNodeServiceProperties(rpcListenHost, rpcListenPort); properties.Render = true; } var nineChroniclesProperties = new NineChroniclesNodeServiceProperties() { Rpc = rpcProperties, Libplanet = properties }; NineChroniclesNodeService nineChroniclesNodeService = StandaloneServices.CreateHeadless(nineChroniclesProperties, standaloneContext); standaloneContext.NineChroniclesNodeService = nineChroniclesNodeService; if (libplanetNode) { if (!properties.NoMiner) { nineChroniclesNodeService.PrivateKey = properties.PrivateKey; nineChroniclesNodeService.StartMining(); } IHostBuilder nineChroniclesNodeHostBuilder = Host.CreateDefaultBuilder(); nineChroniclesNodeHostBuilder = nineChroniclesNodeService.Configure(nineChroniclesNodeHostBuilder); tasks.Add( nineChroniclesNodeHostBuilder.RunConsoleAsync(Context.CancellationToken)); } } catch (Exception e) { Log.Error(e, "Unexpected exception occurred during Run. {e}", e); } finally { await Task.WhenAll(tasks); } #if SENTRY || !DEBUG } catch (CommandExitedException) { throw; } catch (Exception exceptionToCapture) { SentrySdk.CaptureException(exceptionToCapture); throw; } #endif }
public async Task Transfer(string?memo, bool error) { NineChroniclesNodeService service = StandaloneContextFx.NineChroniclesNodeService !; Currency goldCurrency = new GoldCurrencyState( (Dictionary)BlockChain.GetState(GoldCurrencyState.Address) ).Currency; Address senderAddress = service.MinerPrivateKey !.ToAddress(); var store = service.Store; await BlockChain.MineBlock(senderAddress); await BlockChain.MineBlock(senderAddress); // 10 + 10 (mining rewards) Assert.Equal( 20 * goldCurrency, BlockChain.GetBalance(senderAddress, goldCurrency) ); Address recipient = new PrivateKey().ToAddress(); long txNonce = BlockChain.GetNextTxNonce(senderAddress); var args = $"recipient: \"{recipient}\", txNonce: {txNonce}, amount: \"17.5\""; if (!(memo is null)) { args += $"memo: \"{memo}\""; } var query = $"mutation {{ transfer({args}) }}"; ExecutionResult result = await ExecuteQueryAsync(query); if (error) { Assert.NotNull(result.Errors); } else { Assert.Null(result.Errors); var stagedTxIds = BlockChain.GetStagedTransactionIds().ToImmutableList(); Assert.Single(stagedTxIds); string transferTxIdString = stagedTxIds.Single().ToString(); TxId transferTxId = new TxId(ByteUtil.ParseHex(transferTxIdString)); Transaction <NCAction>?tx = BlockChain.StagePolicy.Get(BlockChain, transferTxId, false); Assert.NotNull(tx); Assert.IsType <TransferAsset>(tx !.Actions.Single().InnerAction); TransferAsset transferAsset = (TransferAsset)tx.Actions.Single().InnerAction; Assert.Equal(memo, transferAsset.Memo); var expectedResult = new Dictionary <string, object> { ["transfer"] = transferTxIdString, }; Assert.Equal(expectedResult, result.Data); await BlockChain.MineBlock(recipient); // 10 + 10 - 17.5(transfer) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "2.5"), BlockChain.GetBalance(senderAddress, goldCurrency) ); // 0 + 17.5(transfer) + 10(mining reward) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "27.5"), BlockChain.GetBalance(recipient, goldCurrency) ); } }
public async Task Run( bool noMiner = false, [Option("app-protocol-version", new[] { 'V' }, Description = "App protocol version token")] string appProtocolVersionToken = null, [Option('G')] string genesisBlockPath = null, [Option('H')] string host = null, [Option('P')] ushort?port = null, [Option('D')] int minimumDifficulty = 5000000, [Option("private-key")] string privateKeyString = null, string storeType = null, string storePath = null, [Option("ice-server", new [] { 'I', })] string[] iceServerStrings = null, [Option("peer")] string[] peerStrings = null, [Option("no-trusted-state-validators")] bool noTrustedStateValidators = false, [Option("trusted-app-protocol-version-signer", new[] { 'T' }, Description = "Trustworthy signers who claim new app protocol versions")] string[] trustedAppProtocolVersionSigners = null, bool rpcServer = false, string rpcListenHost = "0.0.0.0", int?rpcListenPort = null, [Option("graphql-server")] bool graphQLServer = false, [Option("graphql-host")] string graphQLHost = "0.0.0.0", [Option("graphql-port")] int?graphQLPort = null, [Option("libplanet-node")] bool libplanetNode = false, [Option("workers", Description = "Number of workers to use in Swarm")] int workers = 5, [Option( "confirmations", Description = "The number of required confirmations to recognize a block. 0 by default." )] int confirmations = 0, [Option( "max-transactions", Description = "The number of maximum transactions can be included in a single block. " + "Unlimited if the value is less then or equal to 0. 100 by default." )] int maximumTransactions = 100, [Option("strict-rendering", Description = "Flag to turn on validating action renderer.")] bool strictRendering = false, [Option("dev", Description = "Flag to turn on the dev mode. false by default.")] bool isDev = false, [Option( "dev.block-interval", Description = "The time interval between blocks. It's unit is milliseconds. Works only when dev mode is on. 10000 (ms) by default.")] int blockInterval = 10000, [Option( "dev.reorg-interval", Description = "The size of reorg interval. Works only when dev mode is on. 0 by default.")] int reorgInterval = 0, [Option(Description = "The log minimum level during headless execution. debug by default.")] string logMinimumLevel = "debug", [Option(Description = "The Cognito identity for AWS CloudWatch logging.")] string awsCognitoIdentity = null, [Option(Description = "The access key for AWS CloudWatch logging.")] string awsAccessKey = null, [Option(Description = "The secret key for AWS CloudWatch logging.")] string awsSecretKey = null, [Option(Description = "The AWS region for AWS CloudWatch (e.g., us-east-1, ap-northeast-2).")] string awsRegion = null ) { #if SENTRY || !DEBUG try { #endif // Setup logger. var loggerConf = new LoggerConfiguration() .WriteTo.Console(outputTemplate: LogTemplate) .ConfigureMinimumLevel(logMinimumLevel); #if SENTRY || !DEBUG loggerConf = loggerConf .WriteTo.Sentry(o => { o.InitializeSdk = false; }); #endif bool useBasicAwsCredentials = !(awsAccessKey is null) && !(awsSecretKey is null); bool useCognitoCredentials = !(awsCognitoIdentity is null); if (useBasicAwsCredentials && useCognitoCredentials) { const string message = "You must choose to use only one credential between basic credential " + "(i.e., --aws-access-key, --aws-secret-key) and " + "Cognito credential (i.e., --aws-cognito-identity)."; throw new CommandExitedException(message, -1); } if (useBasicAwsCredentials ^ useCognitoCredentials && !(awsRegion is null)) { var regionEndpoint = RegionEndpoint.GetBySystemName(awsRegion); AWSCredentials credentials = useCognitoCredentials ? (AWSCredentials) new CognitoAWSCredentials(awsCognitoIdentity, regionEndpoint) : (AWSCredentials) new BasicAWSCredentials(awsAccessKey, awsSecretKey); var guid = LoadAWSSinkGuid() ?? Guid.NewGuid(); StoreAWSSinkGuid(guid); var awsSink = new AWSSink( credentials, regionEndpoint, "9c-standalone-logs", guid.ToString()); loggerConf.WriteTo.Sink(awsSink); } Log.Logger = loggerConf.CreateLogger(); if (!graphQLServer && !libplanetNode) { throw new CommandExitedException( "Either --graphql-server or --libplanet-node must be present.", -1 ); } var tasks = new List <Task>(); try { IHostBuilder graphQLHostBuilder = Host.CreateDefaultBuilder(); var standaloneContext = new StandaloneContext { KeyStore = Web3KeyStore.DefaultKeyStore, }; if (graphQLServer) { var graphQLNodeServiceProperties = new GraphQLNodeServiceProperties { GraphQLServer = graphQLServer, GraphQLListenHost = graphQLHost, GraphQLListenPort = graphQLPort, }; var graphQLService = new GraphQLService(graphQLNodeServiceProperties); graphQLHostBuilder = graphQLService.Configure(graphQLHostBuilder, standaloneContext); tasks.Add(graphQLHostBuilder.RunConsoleAsync(Context.CancellationToken)); await WaitForGraphQLService(graphQLNodeServiceProperties, Context.CancellationToken); } if (appProtocolVersionToken is null) { throw new CommandExitedException( "--app-protocol-version must be present.", -1 ); } if (genesisBlockPath is null) { throw new CommandExitedException( "--genesis-block-path must be present.", -1 ); } RpcNodeServiceProperties?rpcProperties = null; var properties = NineChroniclesNodeServiceProperties .GenerateLibplanetNodeServiceProperties( appProtocolVersionToken, genesisBlockPath, host, port, minimumDifficulty, privateKeyString, storeType, storePath, 100, iceServerStrings, peerStrings, noTrustedStateValidators, trustedAppProtocolVersionSigners, noMiner, workers: workers, confirmations: confirmations, maximumTransactions: maximumTransactions); if (rpcServer) { rpcProperties = NineChroniclesNodeServiceProperties .GenerateRpcNodeServiceProperties(rpcListenHost, rpcListenPort); properties.Render = true; } var nineChroniclesProperties = new NineChroniclesNodeServiceProperties() { Rpc = rpcProperties, Libplanet = properties }; NineChroniclesNodeService nineChroniclesNodeService = StandaloneServices.CreateHeadless( nineChroniclesProperties, standaloneContext, strictRendering: strictRendering, isDev: isDev, blockInterval: blockInterval, reorgInterval: reorgInterval); standaloneContext.NineChroniclesNodeService = nineChroniclesNodeService; if (libplanetNode) { if (!properties.NoMiner) { nineChroniclesNodeService.PrivateKey = properties.PrivateKey; nineChroniclesNodeService.StartMining(); } IHostBuilder nineChroniclesNodeHostBuilder = Host.CreateDefaultBuilder(); nineChroniclesNodeHostBuilder = nineChroniclesNodeService.Configure(nineChroniclesNodeHostBuilder); tasks.Add( nineChroniclesNodeHostBuilder.RunConsoleAsync(Context.CancellationToken)); } await Task.WhenAll(tasks); } catch (TaskCanceledException) { Log.Information("Terminated by the cancellation."); } catch (Exception e) { Log.Error(e, "Unexpected exception occurred during Run. {e}", e); } #if SENTRY || !DEBUG } catch (CommandExitedException) { throw; } catch (Exception exceptionToCapture) { SentrySdk.CaptureException(exceptionToCapture); throw; } #endif }
public async Task ActivationKeyNonce_Throw_ExecutionError(string code, string msg) { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var activatedAccounts = ImmutableHashSet <Address> .Empty; var pendingActivationStates = new List <PendingActivationState>(); Block <PolymorphicAction <ActionBase> > genesis = BlockChain <PolymorphicAction <ActionBase> > .MakeGenesisBlock( HashAlgorithmType.Of <SHA256>(), new PolymorphicAction <ActionBase>[] { new InitializeStates( rankingState: new RankingState(), shopState: new ShopState(), gameConfigState: new GameConfigState(), redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty .Add("address", RedeemCodeState.Address.Serialize()) .Add("map", Bencodex.Types.Dictionary.Empty) ), adminAddressState: new AdminState(adminAddress, 1500000), activatedAccountsState: new ActivatedAccountsState(activatedAccounts), goldCurrencyState: new GoldCurrencyState(new Currency("NCG", 2, minter: null)), goldDistributions: new GoldDistribution[0], tableSheets: _sheets, pendingActivationStates: pendingActivationStates.ToArray() ), } ); var apvPrivateKey = new PrivateKey(); var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); var userPrivateKey = new PrivateKey(); var properties = new LibplanetNodeServiceProperties <PolymorphicAction <ActionBase> > { Host = System.Net.IPAddress.Loopback.ToString(), AppProtocolVersion = apv, GenesisBlock = genesis, StorePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), StoreStatesCacheSize = 2, SwarmPrivateKey = new PrivateKey(), Port = null, NoMiner = true, Render = false, Peers = ImmutableHashSet <Peer> .Empty, TrustedAppProtocolVersionSigners = null, StaticPeers = ImmutableHashSet <BoundPeer> .Empty }; var blockPolicy = NineChroniclesNodeService.GetTestBlockPolicy(); var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, NetworkType.Test); StandaloneContextFx.NineChroniclesNodeService = service; StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; var query = $"query {{ activationKeyNonce(invitationCode: \"{code}\") }}"; var queryResult = await ExecuteQueryAsync(query); Assert.Single(queryResult.Errors); Assert.Equal(msg, queryResult.Errors.First().Message); }
public StandaloneMutation(StandaloneContext standaloneContext) { Field <KeyStoreMutation>( name: "keyStore", resolve: context => standaloneContext.KeyStore); Field <ActivationStatusMutation>( name: "activationStatus", resolve: context => standaloneContext.NineChroniclesNodeService); Field <ActionMutation>( name: "action", resolve: context => standaloneContext.NineChroniclesNodeService); Field <NonNullGraphType <BooleanGraphType> >( name: "stageTx", description: "Add a new transaction to staging", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "payload", Description = "Hex-encoded bytes for new transaction." } ), resolve: context => { try { byte[] bytes = ByteUtil.ParseHex(context.GetArgument <string>("payload")); Transaction <NCAction> tx = Transaction <NCAction> .Deserialize(bytes); NineChroniclesNodeService service = standaloneContext.NineChroniclesNodeService; BlockChain <NCAction> blockChain = service.Swarm.BlockChain; if (blockChain.Policy.DoesTransactionFollowsPolicy(tx, blockChain)) { blockChain.StageTransaction(tx); return(true); } else { context.Errors.Add(new ExecutionError("The given transaction is invalid.")); return(false); } } catch (Exception e) { context.Errors.Add(new ExecutionError("An unexpected exception occurred.", e)); return(false); } } ); Field <TxIdType>( name: "transferGold", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <AddressType> > { Name = "recipient", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "amount" } ), resolve: context => { NineChroniclesNodeService service = standaloneContext.NineChroniclesNodeService; PrivateKey privateKey = service.PrivateKey; if (privateKey is null) { // FIXME We should cover this case on unittest. var msg = "No private key was loaded."; context.Errors.Add(new ExecutionError(msg)); Log.Error(msg); return(null); } BlockChain <NCAction> blockChain = service.BlockChain; var currency = new GoldCurrencyState( (Dictionary)blockChain.GetState(GoldCurrencyState.Address) ).Currency; FungibleAssetValue amount = FungibleAssetValue.Parse(currency, context.GetArgument <string>("amount")); Address recipient = context.GetArgument <Address>("recipient"); Transaction <NCAction> tx = blockChain.MakeTransaction( privateKey, new NCAction[] { new TransferAsset( privateKey.ToAddress(), recipient, amount ), } ); return(tx.Id); } ); }
public async Task ActivateAccount() { var adminPrivateKey = new PrivateKey(); var adminAddress = adminPrivateKey.ToAddress(); var activateAccounts = new[] { adminAddress }.ToImmutableHashSet(); Block <PolymorphicAction <ActionBase> > genesis = BlockChain <PolymorphicAction <ActionBase> > .MakeGenesisBlock( new PolymorphicAction <ActionBase>[] { new InitializeStates() { RankingState = new RankingState(), ShopState = new ShopState(), TableSheetsState = new TableSheetsState(), GameConfigState = new GameConfigState(), RedeemCodeState = new RedeemCodeState(Bencodex.Types.Dictionary.Empty .Add("address", RedeemCodeState.Address.Serialize()) .Add("map", Bencodex.Types.Dictionary.Empty) ), AdminAddressState = new AdminState(adminAddress, 1500000), ActivatedAccountsState = new ActivatedAccountsState(activateAccounts), GoldCurrencyState = new GoldCurrencyState(new Currency("NCG", minter: null)), GoldDistributions = new GoldDistribution[0], }, } ); var apvPrivateKey = new PrivateKey(); var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); var userPrivateKey = new PrivateKey(); var properties = new LibplanetNodeServiceProperties <PolymorphicAction <ActionBase> > { Host = System.Net.IPAddress.Loopback.ToString(), AppProtocolVersion = apv, GenesisBlock = genesis, StorePath = null, StoreStatesCacheSize = 2, PrivateKey = userPrivateKey, Port = null, MinimumDifficulty = 4096, NoMiner = true, Render = false, Peers = ImmutableHashSet <Peer> .Empty, TrustedAppProtocolVersionSigners = null, }; var service = new NineChroniclesNodeService(properties, null); service.PrivateKey = userPrivateKey; StandaloneContextFx.NineChroniclesNodeService = service; StandaloneContextFx.BlockChain = service.Swarm.BlockChain; var blockChain = StandaloneContextFx.BlockChain; var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var privateKey = new PrivateKey(); (ActivationKey activationKey, PendingActivationState pendingActivation) = ActivationKey.Create(privateKey, nonce); PolymorphicAction <ActionBase> action = new CreatePendingActivation(pendingActivation); blockChain.MakeTransaction(adminPrivateKey, new[] { action }); await blockChain.MineBlock(adminAddress); var encodedActivationKey = activationKey.Encode(); var queryResult = await ExecuteQueryAsync( $"mutation {{ activationStatus {{ activateAccount(encodedActivationKey: \"{encodedActivationKey}\") }} }}"); await blockChain.MineBlock(adminAddress); var result = (bool)queryResult.Data .As <Dictionary <string, object> >()["activationStatus"] .As <Dictionary <string, object> >()["activateAccount"]; Assert.True(result); var state = (Bencodex.Types.Dictionary)blockChain.GetState( ActivatedAccountsState.Address); var activatedAccountsState = new ActivatedAccountsState(state); var userAddress = userPrivateKey.ToAddress(); Assert.True(activatedAccountsState.Accounts.Contains(userAddress)); }