diff --git a/Lib9c b/Lib9c
index 9c378d993..b0934580d 160000
--- a/Lib9c
+++ b/Lib9c
@@ -1 +1 @@
-Subproject commit 9c378d99369b8c52bc187b563e47a79bdb8cceaa
+Subproject commit b0934580d7234d586607dcef34c74b8051d8b3b7
diff --git a/Libplanet.Headless.Tests/Hosting/LibplanetNodeServiceTest.cs b/Libplanet.Headless.Tests/Hosting/LibplanetNodeServiceTest.cs
index 6be8af511..8b2d8afec 100644
--- a/Libplanet.Headless.Tests/Hosting/LibplanetNodeServiceTest.cs
+++ b/Libplanet.Headless.Tests/Hosting/LibplanetNodeServiceTest.cs
@@ -31,7 +31,11 @@ public void Constructor()
stateStore);
var actionLoader = new SingleActionLoader(typeof(DummyAction));
var actionEvaluator = new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => policy.BeginBlockActions,
+ _ => policy.EndBlockActions,
+ _ => policy.BeginTxActions,
+ _ => policy.EndTxActions),
stateStore,
actionLoader);
var genesisBlock = BlockChain.ProposeGenesisBlock(actionEvaluator);
diff --git a/Libplanet.Headless/Hosting/LibplanetNodeService.cs b/Libplanet.Headless/Hosting/LibplanetNodeService.cs
index 4e0f063ce..b6eaaadc4 100644
--- a/Libplanet.Headless/Hosting/LibplanetNodeService.cs
+++ b/Libplanet.Headless/Hosting/LibplanetNodeService.cs
@@ -129,7 +129,11 @@ IActionEvaluator BuildActionEvaluator(IActionEvaluatorConfiguration actionEvalua
actionLoader),
DefaultActionEvaluatorConfiguration _ =>
new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
stateStore: StateStore,
actionTypeLoader: actionLoader),
ForkableActionEvaluatorConfiguration forkableActionEvaluatorConfiguration =>
diff --git a/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs
index e21a38c07..79b79ed3b 100644
--- a/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs
+++ b/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs
@@ -48,7 +48,11 @@ public void Balance(StoreType storeType)
IStagePolicy stagePolicy = new VolatileStagePolicy();
IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy();
ActionEvaluator actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader());
BlockChain chain = BlockChain.Create(
diff --git a/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs
index 637bafecc..bce5763dc 100644
--- a/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs
+++ b/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs
@@ -58,7 +58,11 @@ public ChainCommandTest()
public void Tip(StoreType storeType)
{
var actionEvaluator = new ActionEvaluator(
- _ => new BlockPolicy().BlockAction,
+ new PolicyActionsRegistry(
+ _ => new BlockPolicy().BeginBlockActions,
+ _ => new BlockPolicy().EndBlockActions,
+ _ => new BlockPolicy().BeginTxActions,
+ _ => new BlockPolicy().EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesisBlock = BlockChain.ProposeGenesisBlock(actionEvaluator);
@@ -92,7 +96,11 @@ public void Inspect(StoreType storeType)
IStagePolicy stagePolicy = new VolatileStagePolicy();
IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy();
ActionEvaluator actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader());
Block genesisBlock = BlockChain.ProposeGenesisBlock(
@@ -153,7 +161,11 @@ public void Truncate(StoreType storeType)
IStagePolicy stagePolicy = new VolatileStagePolicy();
IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy();
ActionEvaluator actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader());
Block genesisBlock = BlockChain.ProposeGenesisBlock(
@@ -232,7 +244,11 @@ public void PruneState(StoreType storeType)
IStagePolicy stagePolicy = new VolatileStagePolicy();
IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy();
ActionEvaluator actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader());
BlockChain chain = BlockChain.Create(
@@ -284,7 +300,11 @@ public void Snapshot(StoreType storeType)
IStagePolicy stagePolicy = new VolatileStagePolicy();
IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy();
ActionEvaluator actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader());
BlockChain chain = BlockChain.Create(
@@ -445,6 +465,7 @@ private Block MineGenesisBlock()
block.Hash,
DateTimeOffset.UtcNow,
validator.PublicKey,
+ BigInteger.One,
VoteFlag.PreCommit).Sign(validator)))
: null;
}
diff --git a/NineChronicles.Headless.Executable.Tests/Store/StoreExtensionsTest.cs b/NineChronicles.Headless.Executable.Tests/Store/StoreExtensionsTest.cs
index d5d77b991..f06ad3b97 100644
--- a/NineChronicles.Headless.Executable.Tests/Store/StoreExtensionsTest.cs
+++ b/NineChronicles.Headless.Executable.Tests/Store/StoreExtensionsTest.cs
@@ -29,7 +29,11 @@ public void GetGenesisBlock(StoreType storeType)
{
IStore store = storeType.CreateStore(_storePath);
IActionEvaluator actionEvaluator = new ActionEvaluator(
- _ => new BlockPolicy().BlockAction,
+ new PolicyActionsRegistry(
+ _ => new BlockPolicy().BeginBlockActions,
+ _ => new BlockPolicy().EndBlockActions,
+ _ => new BlockPolicy().BeginTxActions,
+ _ => new BlockPolicy().EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesisBlock = BlockChain.ProposeGenesisBlock(actionEvaluator);
diff --git a/NineChronicles.Headless.Executable/Commands/AccountCommand.cs b/NineChronicles.Headless.Executable/Commands/AccountCommand.cs
index 9531c62f4..4e1fb0aec 100644
--- a/NineChronicles.Headless.Executable/Commands/AccountCommand.cs
+++ b/NineChronicles.Headless.Executable/Commands/AccountCommand.cs
@@ -76,7 +76,7 @@ public void Balance(
_console.Error.Flush();
IEnumerable
addrs = digest.TxIds
.Select(txId => store.GetTransaction(new TxId(txId.ToArray())))
- .SelectMany(tx => tx.Actions is { } ca
+ .SelectMany(tx => tx!.Actions is { } ca
? ca.Select(a => ToAction(a))
.SelectMany(a =>
{
diff --git a/NineChronicles.Headless.Executable/Commands/ChainCommand.cs b/NineChronicles.Headless.Executable/Commands/ChainCommand.cs
index 163aacf27..5bbfd1e08 100644
--- a/NineChronicles.Headless.Executable/Commands/ChainCommand.cs
+++ b/NineChronicles.Headless.Executable/Commands/ChainCommand.cs
@@ -17,15 +17,12 @@
using Libplanet.RocksDBStore;
using Libplanet.Store;
using Libplanet.Store.Trie;
-using Microsoft.Extensions.Configuration;
using Nekoyume.Action.Loader;
using Nekoyume.Blockchain.Policy;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NineChronicles.Headless.Executable.IO;
using NineChronicles.Headless.Executable.Store;
-using Serilog;
-using Serilog.Core;
using static NineChronicles.Headless.NCActionUtils;
using CoconaUtils = Libplanet.Extensions.Cocona.Utils;
@@ -82,7 +79,7 @@ public void Tip(
BlockHash tipHash = store.IndexBlockHash(chainId, -1)
?? throw new CommandExitedException("The given chain seems empty.", -1);
- Block tip = store.GetBlock(tipHash);
+ Block tip = store.GetBlock(tipHash)!;
_console.Out.WriteLine(CoconaUtils.SerializeHumanReadable(tip.Header));
store.Dispose();
}
@@ -129,10 +126,14 @@ public void Inspect(
throw new CommandExitedException($"There is no genesis block: {storePath}", -1);
}
- Block genesisBlock = store.GetBlock(gHash);
+ Block genesisBlock = store.GetBlock(gHash)!;
var blockChainStates = new BlockChainStates(store, stateStore);
var actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ beginBlockActionsGetter: _ => blockPolicy.BeginBlockActions,
+ endBlockActionsGetter: _ => blockPolicy.EndBlockActions,
+ beginTxActionsGetter: _ => blockPolicy.BeginTxActions,
+ endTxActionsGetter: _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader());
BlockChain chain = new BlockChain(
@@ -165,10 +166,10 @@ public void Inspect(
{
var block = store.GetBlock(item.value);
var previousBlock = store.GetBlock(
- block.PreviousHash ?? block.Hash
+ block!.PreviousHash ?? block.Hash
);
- var miningTime = block.Timestamp - previousBlock.Timestamp;
+ var miningTime = block.Timestamp - previousBlock!.Timestamp;
var txCount = 0;
var hackAndSlashCount = 0;
var rankingBattleCount = 0;
@@ -286,11 +287,11 @@ public void Truncate(
}
snapshotTipHash = hash;
- } while (!stateStore.GetStateRoot(store.GetBlock(snapshotTipHash).StateRootHash).Recorded);
+ } while (!stateStore.GetStateRoot(store.GetBlock(snapshotTipHash)!.StateRootHash).Recorded);
var forkedId = Guid.NewGuid();
- Fork(chainId, forkedId, snapshotTipHash, tip, store);
+ Fork(chainId, forkedId, snapshotTipHash, tip!, store);
store.SetCanonicalChainId(forkedId);
foreach (var id in store.ListChainIds().Where(id => !id.Equals(forkedId)))
@@ -478,17 +479,21 @@ public void Snapshot(
new BlockPolicy();
var blockChainStates = new BlockChainStates(store, stateStore);
var actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ beginBlockActionsGetter: _ => blockPolicy.BeginBlockActions,
+ endBlockActionsGetter: _ => blockPolicy.EndBlockActions,
+ beginTxActionsGetter: _ => blockPolicy.BeginTxActions,
+ endTxActionsGetter: _ => blockPolicy.EndTxActions),
stateStore,
new NCActionLoader()
);
var originalChain = new BlockChain(blockPolicy, stagePolicy, store, stateStore,
store.GetBlock(genesisHash), blockChainStates, actionEvaluator);
- var tip = store.GetBlock(tipHash);
+ Block tip = store.GetBlock(tipHash)!;
var potentialSnapshotTipIndex = tipIndex - blockBefore;
var potentialSnapshotTipHash = (BlockHash)store.IndexBlockHash(chainId, potentialSnapshotTipIndex)!;
- var snapshotTip = store.GetBlock(potentialSnapshotTipHash);
+ var snapshotTip = store.GetBlock(potentialSnapshotTipHash)!;
_console.Out.WriteLine(
"Original Store Tip: #{0}\n1. LastCommit: {1}\n2. BlockCommit in Chain: {2}\n3. BlockCommit in Store: {3}",
@@ -521,23 +526,27 @@ public void Snapshot(
potentialSnapshotTipIndex);
blockBefore += 1;
potentialSnapshotTipBlockCommit = store
- .GetBlock((BlockHash)store.IndexBlockHash(chainId, tip.Index - blockBefore + 1)!).LastCommit;
+ .GetBlock((BlockHash)store.IndexBlockHash(chainId, tip.Index - blockBefore + 1)!)!.LastCommit;
store.PutBlockCommit(tipBlockCommit);
store.PutChainBlockCommit(chainId, tipBlockCommit);
- store.PutBlockCommit(potentialSnapshotTipBlockCommit);
- store.PutChainBlockCommit(chainId, potentialSnapshotTipBlockCommit);
+ store.PutBlockCommit(potentialSnapshotTipBlockCommit!);
+ store.PutChainBlockCommit(chainId, potentialSnapshotTipBlockCommit!);
}
- var blockCommitBlock = store.GetBlock(tipHash);
+ Block? blockCommitBlock = store.GetBlock(tipHash);
+ if (blockCommitBlock is not { } blockCommitBlockNotNull)
+ {
+ throw new NullReferenceException(nameof(blockChainStates));
+ }
// Add last block commits to store from tip until --block-before + 5 or tip if too short for buffer
var blockCommitRange = blockBefore + 5 < tip.Index ? blockBefore + 5 : tip.Index - 1;
for (var i = 0; i < blockCommitRange; i++)
{
- _console.Out.WriteLine("Adding block #{0}'s block commit to the store", blockCommitBlock.Index - 1);
- store.PutBlockCommit(blockCommitBlock.LastCommit);
- store.PutChainBlockCommit(chainId, blockCommitBlock.LastCommit);
- blockCommitBlock = store.GetBlock((BlockHash)blockCommitBlock.PreviousHash!);
+ _console.Out.WriteLine("Adding block #{0}'s block commit to the store", blockCommitBlockNotNull.Index - 1);
+ store.PutBlockCommit(blockCommitBlockNotNull.LastCommit!);
+ store.PutChainBlockCommit(chainId, blockCommitBlockNotNull.LastCommit!);
+ blockCommitBlock = store.GetBlock((BlockHash)blockCommitBlockNotNull.PreviousHash!);
}
var snapshotTipIndex = Math.Max(tipIndex - (blockBefore + 1), 0);
@@ -555,7 +564,7 @@ public void Snapshot(
}
snapshotTipHash = hash;
- } while (!stateStore.GetStateRoot(store.GetBlock(snapshotTipHash).StateRootHash).Recorded);
+ } while (!stateStore.GetStateRoot(store.GetBlock(snapshotTipHash)!.StateRootHash).Recorded);
var forkedId = Guid.NewGuid();
Fork(chainId, forkedId, snapshotTipHash, tip, store);
@@ -1025,7 +1034,7 @@ private void Fork(
store.ForkBlockIndexes(src, dest, branchPointHash);
if (store.GetBlockCommit(branchPointHash) is { })
{
- store.PutChainBlockCommit(dest, store.GetBlockCommit(branchPointHash));
+ store.PutChainBlockCommit(dest, store.GetBlockCommit(branchPointHash)!);
}
store.ForkTxNonces(src, dest);
@@ -1033,7 +1042,7 @@ private void Fork(
Block block = tip;
block.PreviousHash is { } hash
&& !block.Hash.Equals(branchPointHash);
- block = store.GetBlock(hash))
+ block = store.GetBlock(hash)!)
{
IEnumerable<(Address, int)> signers = block
.Transactions
diff --git a/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs b/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs
index 0cac71bde..6d98029ad 100644
--- a/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs
+++ b/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs
@@ -13,6 +13,7 @@
using Libplanet.Types.Blocks;
using Nekoyume;
using Nekoyume.Action;
+using Nekoyume.Action.DPoS.Misc;
using Nekoyume.Model.State;
using NineChronicles.Headless.Executable.IO;
using CoconaUtils = Libplanet.Extensions.Cocona.Utils;
@@ -236,6 +237,28 @@ out List pledgeActions
}
}
+ private void ProcessInitialNCGConfigs(
+ List? configs,
+ out Dictionary initialNCGs
+ )
+ {
+ _console.Out.WriteLine("\nProcessing initial NCG...");
+
+ initialNCGs = new Dictionary();
+ if (configs is { })
+ {
+ foreach (NCGConfig config in configs)
+ {
+ _console.Out.WriteLine($"Preparing {config.Amount} NCG for {config.Address}...");
+ Address agentAddress = new(config.Address);
+ initialNCGs.Add(
+ agentAddress,
+ new FungibleAssetValue(Asset.GovernanceToken, config.Amount, 0)
+ );
+ }
+ }
+ }
+
[Command(Description = "Mine a new genesis block")]
public void Mine(
[Argument("CONFIG", Description = "JSON config path to mine genesis block")]
@@ -263,6 +286,8 @@ public void Mine(
ProcessInitialPledgeConfigs(genesisConfig.InitialPledgeConfigs, out var initialPledges);
+ ProcessInitialNCGConfigs(genesisConfig.InitialNCGConfigs, out var initialNCGs);
+
// Mine genesis block
_console.Out.WriteLine("\nMining genesis block...\n");
Block block = BlockHelper.ProposeGenesisBlock(
@@ -276,7 +301,8 @@ public void Mine(
item => new PublicKey(ByteUtil.ParseHex(item.PublicKey)),
item => new BigInteger(item.Power)),
actionBases: adminMeads.Concat(initialMeads).Concat(initialPledges).Concat(GetAdditionalActionBases()),
- goldCurrency: currency
+ goldCurrency: currency,
+ initialFavs: initialNCGs
);
Lib9cUtils.ExportBlock(block, "genesis-block");
@@ -418,6 +444,14 @@ private struct PledgeConfig
public int Mead { get; set; }
}
+ [Serializable]
+ private struct NCGConfig
+ {
+ public string Address { get; set; }
+
+ public int Amount { get; set; }
+ }
+
///
/// Config to mine new genesis block.
///
@@ -454,6 +488,8 @@ private struct GenesisConfig
public List? InitialMeadConfigs { get; set; }
public List? InitialPledgeConfigs { get; set; }
+
+ public List? InitialNCGConfigs { get; set; }
}
#pragma warning restore S3459
}
diff --git a/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs b/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs
index 2a5154b23..6ea400753 100644
--- a/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs
+++ b/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs
@@ -8,6 +8,8 @@
using Libplanet.Crypto;
using Libplanet.Action;
using Libplanet.Action.State;
+using Libplanet.Types.Assets;
+using Libplanet.Types.Blocks;
using Libplanet.Types.Tx;
using Serilog;
@@ -28,6 +30,8 @@ public ActionContext(
int blockProtocolVersion,
IWorld previousState,
int randomSeed,
+ bool isBlockAction,
+ FungibleAssetValue? maxGasPrice,
bool rehearsal = false)
{
Signer = signer;
@@ -38,6 +42,8 @@ public ActionContext(
Rehearsal = rehearsal;
PreviousState = previousState;
RandomSeed = randomSeed;
+ IsBlockAction = isBlockAction;
+ MaxGasPrice = maxGasPrice;
}
public Address Signer { get; }
@@ -49,6 +55,8 @@ public ActionContext(
public long BlockIndex { get; }
public int BlockProtocolVersion { get; }
+
+ public BlockCommit? LastCommit { get; }
public bool Rehearsal { get; }
@@ -56,7 +64,9 @@ public ActionContext(
public int RandomSeed { get; }
- public bool BlockAction => TxId is null;
+ public bool IsBlockAction { get; }
+
+ public FungibleAssetValue? MaxGasPrice { get; }
public void UseGas(long gas)
{
@@ -93,6 +103,8 @@ private static IEnumerable EvaluateActions(
Address signer,
byte[] signature,
IImmutableList actions,
+ bool isBlockAction,
+ FungibleAssetValue? maxGasPrice,
ILogger? logger = null)
{
ActionContext CreateActionContext(
@@ -106,7 +118,9 @@ ActionContext CreateActionContext(
blockIndex: blockIndex,
blockProtocolVersion: blockProtocolVersion,
previousState: prevState,
- randomSeed: randomSeed);
+ randomSeed: randomSeed,
+ isBlockAction: isBlockAction,
+ maxGasPrice: maxGasPrice);
}
byte[] preEvaluationHashBytes = preEvaluationHash.ToByteArray();
diff --git a/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs b/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs
index 9e1db0b20..e7193d0c4 100644
--- a/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs
+++ b/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs
@@ -109,8 +109,9 @@ public int Tx(
miner: targetBlock.Miner,
signer: tx.Signer,
signature: tx.Signature,
- actions: actions.Cast().ToImmutableList()
- );
+ actions: actions.Cast().ToImmutableList(),
+ isBlockAction: false,
+ maxGasPrice: tx.MaxGasPrice);
var actionNum = 1;
foreach (var actionEvaluation in actionEvaluations)
{
@@ -405,7 +406,9 @@ public int RemoteTx(
miner: miner,
signer: transaction.Signer,
signature: transaction.Signature,
- actions: actions);
+ actions: actions,
+ isBlockAction: true,
+ maxGasPrice: transaction.MaxGasPrice);
actionEvaluations
.Select((evaluation, index) => (evaluation, index))
@@ -473,7 +476,11 @@ private static (FileStream? fs, StreamWriter? sw) GetOutputFileStream(
var stateStore = new TrieStateStore(stateKeyValueStore);
var blockChainStates = new BlockChainStates(store, stateStore);
var actionEvaluator = new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ beginBlockActionsGetter: _ => policy.BeginBlockActions,
+ endBlockActionsGetter: _ => policy.EndBlockActions,
+ beginTxActionsGetter: _ => policy.BeginTxActions,
+ endTxActionsGetter: _ => policy.EndTxActions),
stateStore,
new NCActionLoader());
return (
@@ -520,7 +527,11 @@ private ActionEvaluator GetActionEvaluator(IStateStore stateStore)
var policy = new BlockPolicySource().GetPolicy();
IActionLoader actionLoader = new NCActionLoader();
return new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ beginBlockActionsGetter: _ => policy.BeginBlockActions,
+ endBlockActionsGetter: _ => policy.EndBlockActions,
+ beginTxActionsGetter: _ => policy.BeginTxActions,
+ endTxActionsGetter: _ => policy.EndTxActions),
stateStore: stateStore,
actionTypeLoader: actionLoader);
}
diff --git a/NineChronicles.Headless.Executable/Commands/StateCommand.cs b/NineChronicles.Headless.Executable/Commands/StateCommand.cs
index 28a930868..a5dd14942 100644
--- a/NineChronicles.Headless.Executable/Commands/StateCommand.cs
+++ b/NineChronicles.Headless.Executable/Commands/StateCommand.cs
@@ -109,7 +109,11 @@ IStateStore stateStore
new MemoryStore(),
sStore);
var actionEvaluator = new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ beginBlockActionsGetter: _ => policy.BeginBlockActions,
+ endBlockActionsGetter: _ => policy.EndBlockActions,
+ beginTxActionsGetter: _ => policy.BeginTxActions,
+ endTxActionsGetter: _ => policy.EndTxActions),
sStore,
new NCActionLoader());
@@ -120,8 +124,7 @@ IStateStore stateStore
throw new CommandExitedException(1);
}
- Block block =
- store.GetBlock(blockHash);
+ Block block = store.GetBlock(blockHash)!;
var preEvalBlock = new PreEvaluationBlock(
block,
block.Transactions
diff --git a/NineChronicles.Headless.Executable/Store/StoreExtensions.cs b/NineChronicles.Headless.Executable/Store/StoreExtensions.cs
index e2d56f7ee..9d083f0b2 100644
--- a/NineChronicles.Headless.Executable/Store/StoreExtensions.cs
+++ b/NineChronicles.Headless.Executable/Store/StoreExtensions.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Linq;
using Libplanet.Action;
@@ -18,7 +17,7 @@ public static Block GetGenesisBlock(this IStore store)
}
BlockHash genesisBlockHash = store.IterateIndexes(chainId.Value).First();
- Block genesisBlock = store.GetBlock(genesisBlockHash);
+ Block genesisBlock = store.GetBlock(genesisBlockHash)!;
return genesisBlock;
}
}
diff --git a/NineChronicles.Headless.Tests/Common/MockAccount.cs b/NineChronicles.Headless.Tests/Common/MockAccount.cs
index ac2d3acdd..705325e29 100644
--- a/NineChronicles.Headless.Tests/Common/MockAccount.cs
+++ b/NineChronicles.Headless.Tests/Common/MockAccount.cs
@@ -188,6 +188,9 @@ public IAccount BurnAsset(
public IAccount SetValidator(Validator validator) =>
UpdateValidatorSet(GetValidatorSet().Update(validator));
+ public IAccount SetValidatorSet(ValidatorSet validatorSet) =>
+ UpdateValidatorSet(validatorSet);
+
[Pure]
private MockAccount UpdateState(
Address address,
diff --git a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs
index 58c7f7eab..fed795418 100644
--- a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs
+++ b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs
@@ -83,7 +83,11 @@ public static StandaloneContext CreateStandaloneContext()
var stateStore = new TrieStateStore(new DefaultKeyValueStore(null));
var policy = new BlockPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => policy.BeginBlockActions,
+ _ => policy.EndBlockActions,
+ _ => policy.BeginTxActions,
+ _ => policy.EndTxActions),
stateStore,
new NCActionLoader());
var genesisBlock = BlockChain.ProposeGenesisBlock(actionEvaluator);
@@ -114,7 +118,11 @@ PrivateKey minerPrivateKey
var stateStore = new TrieStateStore(new DefaultKeyValueStore(null));
var policy = new BlockPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => policy.BeginBlockActions,
+ _ => policy.EndBlockActions,
+ _ => policy.BeginTxActions,
+ _ => policy.EndTxActions),
stateStore,
new NCActionLoader());
var genesisBlock = BlockChain.ProposeGenesisBlock(
diff --git a/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs b/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs
index d7393fbf7..b45544602 100644
--- a/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs
+++ b/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs
@@ -35,6 +35,7 @@
using System.Threading.Tasks;
using Bencodex.Types;
using Libplanet.Types.Tx;
+using Nekoyume.Action.DPoS;
using Xunit.Abstractions;
namespace NineChronicles.Headless.Tests.GraphTypes
@@ -55,9 +56,12 @@ public GraphQLTestBase(ITestOutputHelper output)
#pragma warning restore CS0618
var sheets = TableSheetsImporter.ImportSheets();
- var blockAction = new RewardGold();
var actionEvaluator = new ActionEvaluator(
- _ => blockAction,
+ new PolicyActionsRegistry(
+ _ => new DebugPolicy().BeginBlockActions,
+ _ => new DebugPolicy().EndBlockActions,
+ _ => new DebugPolicy().BeginTxActions,
+ _ => new DebugPolicy().EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
var genesisBlock = BlockChain.ProposeGenesisBlock(
@@ -250,6 +254,7 @@ protected LibplanetNodeService CreateLibplanetNodeService(
hash,
DateTimeOffset.UtcNow,
validator.PublicKey,
+ BigInteger.One,
VoteFlag.PreCommit).Sign(validator)).ToImmutableArray())
: (BlockCommit?)null;
}
diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs
index 1adb11f11..0ea3dc9f0 100644
--- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs
+++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs
@@ -919,7 +919,11 @@ private Block MakeGenesisBlock(
RankingState0? rankingState = null)
{
var actionEvaluator = new ActionEvaluator(
- _ => ServiceBuilder.BlockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => ServiceBuilder.BlockPolicy.BeginBlockActions,
+ _ => ServiceBuilder.BlockPolicy.EndBlockActions,
+ _ => ServiceBuilder.BlockPolicy.BeginTxActions,
+ _ => ServiceBuilder.BlockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
return BlockChain.ProposeGenesisBlock(
diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs
index 4b36b5309..860788f38 100644
--- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs
+++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs
@@ -15,6 +15,7 @@
using Libplanet.Action.State;
using Libplanet.Action.Sys;
using Libplanet.Blockchain;
+using Libplanet.Blockchain.Policies;
using Libplanet.Common;
using Libplanet.Crypto;
using Libplanet.Headless.Hosting;
@@ -119,8 +120,13 @@ public async Task NodeStatus()
var apvPrivateKey = new PrivateKey();
var apv = AppProtocolVersion.Sign(apvPrivateKey, 0);
+ var blockPolicy = new BlockPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => null,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
var genesisBlock = BlockChain.ProposeGenesisBlock(actionEvaluator);
@@ -447,8 +453,13 @@ public async Task ActivationStatus(bool existsActivatedAccounts)
{
new Libplanet.Types.Consensus.Validator(ProposerPrivateKey.PublicKey, BigInteger.One),
}.ToList());
+ var blockPolicy = new BlockPolicySource().GetPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => null,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesis =
@@ -513,7 +524,6 @@ public async Task ActivationStatus(bool existsActivatedAccounts)
ConsensusSeeds = ImmutableList.Empty,
ConsensusPeers = ImmutableList.Empty
};
- var blockPolicy = new BlockPolicySource().GetPolicy();
var service = new NineChroniclesNodeService(
userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance);
@@ -840,8 +850,13 @@ public async Task ActivationKeyNonce(bool trim)
{
pendingActivation,
};
+ var blockPolicy = NineChroniclesNodeService.GetBlockPolicy(Planet.Odin, StaticActionLoaderSingleton.Instance);
var actionEvaluator = new ActionEvaluator(
- _ => null,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesis =
@@ -897,7 +912,6 @@ public async Task ActivationKeyNonce(bool trim)
ConsensusPeers = ImmutableList.Empty
};
- var blockPolicy = NineChroniclesNodeService.GetBlockPolicy(Planet.Odin, StaticActionLoaderSingleton.Instance);
var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance);
StandaloneContextFx.NineChroniclesNodeService = service;
StandaloneContextFx.BlockChain = service.Swarm?.BlockChain;
@@ -925,8 +939,13 @@ public async Task ActivationKeyNonce_Throw_ExecutionError(string code, string ms
var activatedAccounts = ImmutableHashSet.Empty;
var pendingActivationStates = new List();
+ var blockPolicy = new BlockPolicySource().GetPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => null,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesis =
@@ -984,7 +1003,6 @@ public async Task ActivationKeyNonce_Throw_ExecutionError(string code, string ms
ConsensusSeeds = ImmutableList.Empty,
ConsensusPeers = ImmutableList.Empty
};
- var blockPolicy = new BlockPolicySource().GetPolicy();
var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance);
StandaloneContextFx.NineChroniclesNodeService = service;
@@ -1006,8 +1024,13 @@ public async Task Balance()
var activatedAccounts = ImmutableHashSet.Empty;
var pendingActivationStates = new List();
+ var blockPolicy = new BlockPolicySource().GetPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => null,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesis =
@@ -1062,7 +1085,6 @@ public async Task Balance()
ConsensusSeeds = ImmutableList.Empty,
ConsensusPeers = ImmutableList.Empty
};
- var blockPolicy = new BlockPolicySource().GetPolicy();
var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance);
StandaloneContextFx.NineChroniclesNodeService = service;
@@ -1112,7 +1134,11 @@ private NineChroniclesNodeService MakeNineChroniclesNodeService(PrivateKey priva
new Libplanet.Types.Consensus.Validator(privateKey.PublicKey, BigInteger.One),
}.ToList());
var actionEvaluator = new ActionEvaluator(
- _ => blockPolicy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new NCActionLoader());
Block genesis =
diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs
index 8c3fc52ea..097c64ce2 100644
--- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs
+++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs
@@ -19,6 +19,7 @@
using Libplanet.Types.Assets;
using Libplanet.Types.Blocks;
using Libplanet.Blockchain;
+using Libplanet.Blockchain.Policies;
using Libplanet.Types.Consensus;
using Libplanet.Crypto;
using Libplanet.Headless;
@@ -133,8 +134,13 @@ public async Task SubscribePreloadProgress()
var apvPrivateKey = new PrivateKey();
var apv = AppProtocolVersion.Sign(apvPrivateKey, 0);
+ var blockPolicy = new BlockPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => null,
+ new PolicyActionsRegistry(
+ _ => blockPolicy.BeginBlockActions,
+ _ => blockPolicy.EndBlockActions,
+ _ => blockPolicy.BeginTxActions,
+ _ => blockPolicy.EndTxActions),
new TrieStateStore(new MemoryKeyValueStore()),
new SingleActionLoader(typeof(EmptyAction)));
var genesisBlock = BlockChain.ProposeGenesisBlock(
diff --git a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs
index 62e3d68bf..168457917 100644
--- a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs
+++ b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs
@@ -45,7 +45,11 @@ public TransactionHeadlessQueryTest()
_stateStore = new TrieStateStore(new DefaultKeyValueStore(null));
IBlockPolicy policy = new BlockPolicySource().GetPolicy();
var actionEvaluator = new ActionEvaluator(
- _ => policy.BlockAction,
+ new PolicyActionsRegistry(
+ _ => policy.BeginBlockActions,
+ _ => policy.EndTxActions,
+ _ => policy.BeginTxActions,
+ _ => policy.EndTxActions),
_stateStore,
new NCActionLoader());
Block genesisBlock = BlockChain.ProposeGenesisBlock(
@@ -428,6 +432,7 @@ private Task ExecuteAsync(string query)
hash,
DateTimeOffset.UtcNow,
validator.PublicKey,
+ BigInteger.One,
VoteFlag.PreCommit).Sign(validator)))
: (BlockCommit?)null;
}
diff --git a/NineChronicles.Headless/ActionEvaluationPublisher.cs b/NineChronicles.Headless/ActionEvaluationPublisher.cs
index bba680fd1..152a0cc99 100644
--- a/NineChronicles.Headless/ActionEvaluationPublisher.cs
+++ b/NineChronicles.Headless/ActionEvaluationPublisher.cs
@@ -20,7 +20,6 @@
using Grpc.Net.Client;
using Lib9c.Renderers;
using Libplanet.Action.State;
-using Libplanet.Blockchain;
using Libplanet.Common;
using Libplanet.Crypto;
using Libplanet.Types.Blocks;
@@ -32,6 +31,8 @@
using Microsoft.Extensions.Options;
using Nekoyume;
using Nekoyume.Action;
+using Nekoyume.Action.DPoS;
+using Nekoyume.Action.DPoS.Sys;
using Nekoyume.Shared.Hubs;
using Serilog;
@@ -471,9 +472,7 @@ await _hub.BroadcastRenderBlockAsync(
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
- ActionBase? pa = ev.Action is RewardGold
- ? null
- : ev.Action;
+ ActionBase pa = ev.Action;
var extra = new Dictionary();
var encodeElapsedMilliseconds = stopwatch.ElapsedMilliseconds;
diff --git a/NineChronicles.Headless/BlockChainContext.cs b/NineChronicles.Headless/BlockChainContext.cs
index 0fc1eb096..0e570a630 100644
--- a/NineChronicles.Headless/BlockChainContext.cs
+++ b/NineChronicles.Headless/BlockChainContext.cs
@@ -16,9 +16,9 @@ public BlockChainContext(StandaloneContext standaloneContext)
}
public bool Preloaded => _standaloneContext.NodeStatus.PreloadEnded;
- public BlockChain? BlockChain => _standaloneContext.BlockChain;
- public IStore? Store => _standaloneContext.Store;
- public Swarm? Swarm => _standaloneContext.Swarm;
+ public BlockChain BlockChain => _standaloneContext.BlockChain!;
+ public IStore Store => _standaloneContext.Store!;
+ public Swarm Swarm => _standaloneContext.Swarm!;
public IBlockChainIndex Index => new RocksDbBlockChainIndex("/tmp/no/no/no/store");
}
}
diff --git a/NineChronicles.Headless/GraphTypes/ActionMutation.cs b/NineChronicles.Headless/GraphTypes/ActionMutation.cs
index 17e9f7e66..8691126f6 100644
--- a/NineChronicles.Headless/GraphTypes/ActionMutation.cs
+++ b/NineChronicles.Headless/GraphTypes/ActionMutation.cs
@@ -5,11 +5,13 @@
using Libplanet.Explorer.GraphTypes;
using Libplanet.Types.Tx;
using Nekoyume.Action;
-using Nekoyume.Model.State;
using Serilog;
using System;
using System.Collections.Generic;
-using Nekoyume.Module;
+using System.Numerics;
+using Libplanet.Types.Assets;
+using Nekoyume.Action.DPoS;
+using Nekoyume.Action.DPoS.Misc;
namespace NineChronicles.Headless.GraphTypes
{
@@ -438,6 +440,98 @@ public ActionMutation(NineChroniclesNodeService service)
}
}
);
+
+ Field>("promoteValidator",
+ description: "Promote validator.",
+ arguments: new QueryArguments(
+ new QueryArgument>
+ {
+ Name = "validator",
+ Description = "Validator public key to promote."
+ },
+ new QueryArgument>
+ {
+ Name = "amount",
+ Description = "Amount of NCG to stake."
+ }
+ ),
+ resolve: context =>
+ {
+ try
+ {
+ Console.WriteLine("[PromoteValidator] PromoteValidator called");
+ BlockChain? blockChain = service.BlockChain;
+ if (blockChain is null)
+ {
+ throw new InvalidOperationException($"{nameof(blockChain)} is null.");
+ }
+
+ Console.WriteLine("[PromoteValidator] BlockChain is not null");
+ string validatorString = context.GetArgument("validator");
+ PublicKey validator = PublicKey.FromHex(validatorString);
+ BigInteger amount = context.GetArgument("amount");
+ Console.WriteLine($"[PromoteValidator] Validator: {validator}, amount: {amount}");
+ var fav = new FungibleAssetValue(Asset.GovernanceToken, amount, 0);
+
+ var action = new PromoteValidator(validator, fav);
+ Console.WriteLine("[PromoteValidator] PromoteValidator action successfully created");
+
+ var actions = new[] { action };
+ Transaction tx = blockChain.MakeTransaction(service.MinerPrivateKey, actions);
+ Console.WriteLine("[PromoteValidator] PromoteValidator transaction staged");
+ return tx.Id;
+ }
+ catch (Exception e)
+ {
+ var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}";
+ context.Errors.Add(new ExecutionError(msg, e));
+ throw;
+ }
+ }
+ );
+
+ Field>("delegate",
+ description: "Promote validator.",
+ arguments: new QueryArguments(
+ new QueryArgument>
+ {
+ Name = "validator",
+ Description = "Validator address to delegate."
+ },
+ new QueryArgument>
+ {
+ Name = "amount",
+ Description = "Amount of NCG to delegate."
+ }
+ ),
+ resolve: context =>
+ {
+ try
+ {
+ BlockChain? blockChain = service.BlockChain;
+ if (blockChain is null)
+ {
+ throw new InvalidOperationException($"{nameof(blockChain)} is null.");
+ }
+
+ Address validator = context.GetArgument("validator");
+ BigInteger amount = context.GetArgument("amount");
+ var fav = new FungibleAssetValue(Asset.GovernanceToken, amount, 0);
+
+ var action = new Nekoyume.Action.DPoS.Delegate(validator, fav);
+
+ var actions = new[] { action };
+ Transaction tx = blockChain.MakeTransaction(service.MinerPrivateKey, actions);
+ return tx.Id;
+ }
+ catch (Exception e)
+ {
+ var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}";
+ context.Errors.Add(new ExecutionError(msg, e));
+ throw;
+ }
+ }
+ );
}
}
}
diff --git a/NineChronicles.Headless/GraphTypes/AppProtocolVersionType.cs b/NineChronicles.Headless/GraphTypes/AppProtocolVersionType.cs
index 87cb9b00a..2c8b4db0c 100644
--- a/NineChronicles.Headless/GraphTypes/AppProtocolVersionType.cs
+++ b/NineChronicles.Headless/GraphTypes/AppProtocolVersionType.cs
@@ -22,7 +22,7 @@ public AppProtocolVersionType()
resolve: context => context.Source.Signature.ToBuilder().ToArray());
Field(
name: "extra",
- resolve: context => _codec.Encode(context.Source.Extra));
+ resolve: context => _codec.Encode(context.Source.Extra!));
}
}
}
diff --git a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs
index afd2f7471..1a3f3ccbd 100644
--- a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs
+++ b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs
@@ -134,20 +134,20 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi
IEnumerable blockTxs = digest.TxIds
.Select(bytes => new TxId(bytes))
- .Select(store.GetTransaction);
+ .Select(store.GetTransaction)!;
var filtered = blockTxs
.Where(tx => tx.Actions.Count == 1)
.Select(tx => (store.GetTxExecution(blockHash, tx.Id), ToAction(tx.Actions[0])))
.Where(pair => pair.Item1 is { } && pair.Item2 is ITransferAsset)
.Select(pair => (pair.Item1, (ITransferAsset)pair.Item2))
- .Where(pair => !pair.Item1.Fail &&
+ .Where(pair => !pair.Item1!.Fail &&
(!recipient.HasValue || pair.Item2.Recipient == recipient) &&
pair.Item2.Amount.Currency.Ticker == "NCG");
var histories = filtered.Select(pair =>
new TransferNCGHistory(
- pair.Item1.BlockHash,
+ pair.Item1!.BlockHash,
pair.Item1.TxId,
pair.Item2.Sender,
pair.Item2.Recipient,
diff --git a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs
index 0b5cb3694..f5355c27b 100644
--- a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs
+++ b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs
@@ -298,7 +298,7 @@ private IObservable SubscribeTx(IResolveFieldContext context)
var txExecution = store.GetTxExecution(blockHash, transaction.Id);
var txExecutedBlock = chain[blockHash];
return new TxResult(
- txExecution.Fail ? TxStatus.FAILURE : TxStatus.SUCCESS,
+ txExecution!.Fail ? TxStatus.FAILURE : TxStatus.SUCCESS,
txExecutedBlock.Index,
txExecutedBlock.Hash.ToString(),
txExecution.InputState,
diff --git a/NineChronicles.Headless/Properties/NineChroniclesNodeServiceProperties.cs b/NineChronicles.Headless/Properties/NineChroniclesNodeServiceProperties.cs
index 5121e961b..c68f424a5 100644
--- a/NineChronicles.Headless/Properties/NineChroniclesNodeServiceProperties.cs
+++ b/NineChronicles.Headless/Properties/NineChroniclesNodeServiceProperties.cs
@@ -112,7 +112,7 @@ public static LibplanetNodeServiceProperties
Host = swarmHost,
Port = swarmPort,
SwarmPrivateKey = swarmPrivateKey,
- AppProtocolVersion = AppProtocolVersion.FromToken(appProtocolVersionToken),
+ AppProtocolVersion = AppProtocolVersion.FromToken(appProtocolVersionToken!),
TrustedAppProtocolVersionSigners = trustedAppProtocolVersionSigners
?.Select(s => new PublicKey(ByteUtil.ParseHex(s)))
?.ToHashSet(),