diff --git a/src/Plugins/StateService/Network/StateRoot.cs b/src/Plugins/StateService/Network/StateRoot.cs index 5be191f4da..35cd9734aa 100644 --- a/src/Plugins/StateService/Network/StateRoot.cs +++ b/src/Plugins/StateService/Network/StateRoot.cs @@ -9,7 +9,6 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.Cryptography.ECC; using Neo.Extensions; using Neo.IO; using Neo.Json; @@ -49,7 +48,7 @@ Witness[] IVerifiable.Witnesses { get { - return new[] { Witness }; + return [Witness]; } set { @@ -70,12 +69,12 @@ Witness[] IVerifiable.Witnesses void ISerializable.Deserialize(ref MemoryReader reader) { DeserializeUnsigned(ref reader); - Witness[] witnesses = reader.ReadSerializableArray(1); + var witnesses = reader.ReadSerializableArray(1); Witness = witnesses.Length switch { 0 => null, 1 => witnesses[0], - _ => throw new FormatException(), + _ => throw new FormatException($"Expected 1 witness, got {witnesses.Length}."), }; } @@ -92,7 +91,7 @@ void ISerializable.Serialize(BinaryWriter writer) if (Witness is null) writer.WriteVarInt(0); else - writer.Write(new[] { Witness }); + writer.Write([Witness]); } public void SerializeUnsigned(BinaryWriter writer) @@ -109,19 +108,20 @@ public bool Verify(ProtocolSettings settings, DataCache snapshot) public UInt160[] GetScriptHashesForVerifying(DataCache snapshot) { - ECPoint[] validators = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.StateValidator, Index); + var validators = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.StateValidator, Index); if (validators.Length < 1) throw new InvalidOperationException("No script hash for state root verifying"); - return new UInt160[] { Contract.GetBFTAddress(validators) }; + return [Contract.GetBFTAddress(validators)]; } public JObject ToJson() { - var json = new JObject(); - json["version"] = Version; - json["index"] = Index; - json["roothash"] = RootHash.ToString(); - json["witnesses"] = Witness is null ? new JArray() : new JArray(Witness.ToJson()); - return json; + return new() + { + ["version"] = Version, + ["index"] = Index, + ["roothash"] = RootHash.ToString(), + ["witnesses"] = Witness is null ? new JArray() : new JArray(Witness.ToJson()), + }; } } } diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index 559e2a6f15..0118e20efb 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -18,7 +18,6 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.Plugins.RpcServer; -using Neo.Plugins.StateService.Network; using Neo.Plugins.StateService.Storage; using Neo.Plugins.StateService.Verification; using Neo.SmartContract; @@ -45,7 +44,10 @@ public class StatePlugin : Plugin, ICommittingHandler, ICommittedHandler, IWalle internal IActorRef Store; internal IActorRef Verifier; - internal static NeoSystem _system; + private static NeoSystem _system; + + internal static NeoSystem NeoSystem => _system; + private IWalletProvider walletProvider; public StatePlugin() @@ -96,10 +98,14 @@ public override void Dispose() if (Verifier is not null) _system.EnsureStopped(Verifier); } - void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, + IReadOnlyList applicationExecutedList) { if (system.Settings.Network != Settings.Default.Network) return; - StateStore.Singleton.UpdateLocalStateRootSnapshot(block.Index, snapshot.GetChangeSet().Where(p => p.Value.State != TrackState.None).Where(p => p.Key.Id != NativeContract.Ledger.Id).ToList()); + StateStore.Singleton.UpdateLocalStateRootSnapshot(block.Index, + snapshot.GetChangeSet() + .Where(p => p.Value.State != TrackState.None && p.Key.Id != NativeContract.Ledger.Id) + .ToList()); } void ICommittedHandler.Blockchain_Committed_Handler(NeoSystem system, Block block) @@ -108,10 +114,17 @@ void ICommittedHandler.Blockchain_Committed_Handler(NeoSystem system, Block bloc StateStore.Singleton.UpdateLocalStateRoot(block.Index); } + private void CheckNetwork() + { + var network = Settings.Default.Network; + if (_system is null || _system.Settings.Network != network) + throw new InvalidOperationException($"Network doesn't match: {_system?.Settings.Network} != {network}"); + } + [ConsoleCommand("start states", Category = "StateService", Description = "Start as a state verifier if wallet is open")] private void OnStartVerifyingState() { - if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + CheckNetwork(); Start(walletProvider.GetWallet()); } @@ -133,19 +146,21 @@ public void Start(Wallet wallet) [ConsoleCommand("state root", Category = "StateService", Description = "Get state root by index")] private void OnGetStateRoot(uint index) { - if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + CheckNetwork(); + using var snapshot = StateStore.Singleton.GetSnapshot(); - StateRoot state_root = snapshot.GetStateRoot(index); - if (state_root is null) + var stateRoot = snapshot.GetStateRoot(index); + if (stateRoot is null) ConsoleHelper.Warning("Unknown state root"); else - ConsoleHelper.Info(state_root.ToJson().ToString()); + ConsoleHelper.Info(stateRoot.ToJson().ToString()); } [ConsoleCommand("state height", Category = "StateService", Description = "Get current state root index")] private void OnGetStateHeight() { - if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + CheckNetwork(); + ConsoleHelper.Info("LocalRootIndex: ", $"{StateStore.Singleton.LocalRootIndex}", " ValidatedRootIndex: ", @@ -153,12 +168,12 @@ private void OnGetStateHeight() } [ConsoleCommand("get proof", Category = "StateService", Description = "Get proof of key and contract hash")] - private void OnGetProof(UInt256 root_hash, UInt160 script_hash, string key) + private void OnGetProof(UInt256 rootHash, UInt160 scriptHash, string key) { if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); try { - ConsoleHelper.Info("Proof: ", GetProof(root_hash, script_hash, Convert.FromBase64String(key))); + ConsoleHelper.Info("Proof: ", GetProof(rootHash, scriptHash, Convert.FromBase64String(key))); } catch (RpcException e) { @@ -167,12 +182,12 @@ private void OnGetProof(UInt256 root_hash, UInt160 script_hash, string key) } [ConsoleCommand("verify proof", Category = "StateService", Description = "Verify proof, return value if successed")] - private void OnVerifyProof(UInt256 root_hash, string proof) + private void OnVerifyProof(UInt256 rootHash, string proof) { try { ConsoleHelper.Info("Verify Result: ", - VerifyProof(root_hash, Convert.FromBase64String(proof))); + VerifyProof(rootHash, Convert.FromBase64String(proof))); } catch (RpcException e) { @@ -183,17 +198,17 @@ private void OnVerifyProof(UInt256 root_hash, string proof) [RpcMethod] public JToken GetStateRoot(JArray _params) { - uint index = Result.Ok_Or(() => uint.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid state root index: {_params[0]}")); + var index = Result.Ok_Or(() => uint.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid state root index: {_params[0]}")); using var snapshot = StateStore.Singleton.GetSnapshot(); - StateRoot state_root = snapshot.GetStateRoot(index).NotNull_Or(RpcError.UnknownStateRoot); - return state_root.ToJson(); + var stateRoot = snapshot.GetStateRoot(index).NotNull_Or(RpcError.UnknownStateRoot); + return stateRoot.ToJson(); } - private string GetProof(Trie trie, int contract_id, byte[] key) + private string GetProof(Trie trie, int contractId, byte[] key) { - StorageKey skey = new() + var skey = new StorageKey() { - Id = contract_id, + Id = contractId, Key = key, }; return GetProof(trie, skey); @@ -202,8 +217,8 @@ private string GetProof(Trie trie, int contract_id, byte[] key) private string GetProof(Trie trie, StorageKey skey) { trie.TryGetProof(skey.ToArray(), out var proof).True_Or(RpcError.UnknownStorageItem); - using MemoryStream ms = new(); - using BinaryWriter writer = new(ms, Utility.StrictUTF8); + using var ms = new MemoryStream(); + using var writer = new BinaryWriter(ms, Utility.StrictUTF8); writer.WriteVarBytes(skey.ToArray()); writer.WriteVarInt(proof.Count); @@ -216,30 +231,31 @@ private string GetProof(Trie trie, StorageKey skey) return Convert.ToBase64String(ms.ToArray()); } - private string GetProof(UInt256 root_hash, UInt160 script_hash, byte[] key) + private string GetProof(UInt256 rootHash, UInt160 scriptHash, byte[] key) { - (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != root_hash).False_Or(RpcError.UnsupportedState); + (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != rootHash).False_Or(RpcError.UnsupportedState); + using var store = StateStore.Singleton.GetStoreSnapshot(); - var trie = new Trie(store, root_hash); - var contract = GetHistoricalContractState(trie, script_hash).NotNull_Or(RpcError.UnknownContract); + var trie = new Trie(store, rootHash); + var contract = GetHistoricalContractState(trie, scriptHash).NotNull_Or(RpcError.UnknownContract); return GetProof(trie, contract.Id, key); } [RpcMethod] public JToken GetProof(JArray _params) { - UInt256 root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); - UInt160 script_hash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); - byte[] key = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[2]}")); - return GetProof(root_hash, script_hash, key); + var rootHash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + var scriptHash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); + var key = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[2]}")); + return GetProof(rootHash, scriptHash, key); } - private string VerifyProof(UInt256 root_hash, byte[] proof) + private string VerifyProof(UInt256 rootHash, byte[] proof) { var proofs = new HashSet(); - using MemoryStream ms = new(proof, false); - using BinaryReader reader = new(ms, Utility.StrictUTF8); + using var ms = new MemoryStream(proof, false); + using var reader = new BinaryReader(ms, Utility.StrictUTF8); var key = reader.ReadVarBytes(Node.MaxKeyLength); var count = reader.ReadVarInt(byte.MaxValue); @@ -248,31 +264,32 @@ private string VerifyProof(UInt256 root_hash, byte[] proof) proofs.Add(reader.ReadVarBytes()); } - var value = Trie.VerifyProof(root_hash, key, proofs).NotNull_Or(RpcError.InvalidProof); + var value = Trie.VerifyProof(rootHash, key, proofs).NotNull_Or(RpcError.InvalidProof); return Convert.ToBase64String(value); } [RpcMethod] public JToken VerifyProof(JArray _params) { - UInt256 root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); - byte[] proof_bytes = Result.Ok_Or(() => Convert.FromBase64String(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid proof: {_params[1]}")); - return VerifyProof(root_hash, proof_bytes); + var rootHash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + var proofBytes = Result.Ok_Or(() => Convert.FromBase64String(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid proof: {_params[1]}")); + return VerifyProof(rootHash, proofBytes); } [RpcMethod] public JToken GetStateHeight(JArray _params) { - var json = new JObject(); - json["localrootindex"] = StateStore.Singleton.LocalRootIndex; - json["validatedrootindex"] = StateStore.Singleton.ValidatedRootIndex; - return json; + return new JObject() + { + ["localrootindex"] = StateStore.Singleton.LocalRootIndex, + ["validatedrootindex"] = StateStore.Singleton.ValidatedRootIndex, + }; } - private ContractState GetHistoricalContractState(Trie trie, UInt160 script_hash) + private ContractState GetHistoricalContractState(Trie trie, UInt160 scriptHash) { const byte prefix = 8; - StorageKey skey = new KeyBuilder(NativeContract.ContractManagement.Id, prefix).Add(script_hash); + StorageKey skey = new KeyBuilder(NativeContract.ContractManagement.Id, prefix).Add(scriptHash); return trie.TryGetValue(skey.ToArray(), out var value) ? value.AsSerializable().GetInteroperable() : null; } @@ -288,43 +305,48 @@ private StorageKey ParseStorageKey(byte[] data) [RpcMethod] public JToken FindStates(JArray _params) { - var root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); - (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != root_hash).False_Or(RpcError.UnsupportedState); - var script_hash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); + var rootHash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != rootHash).False_Or(RpcError.UnsupportedState); + + var scriptHash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); var prefix = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid prefix: {_params[2]}")); - byte[] key = Array.Empty(); + var key = Array.Empty(); if (3 < _params.Count) key = Result.Ok_Or(() => Convert.FromBase64String(_params[3].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[3]}")); + int count = Settings.Default.MaxFindResultItems; if (4 < _params.Count) count = Result.Ok_Or(() => int.Parse(_params[4].AsString()), RpcError.InvalidParams.WithData($"Invalid count: {_params[4]}")); if (Settings.Default.MaxFindResultItems < count) count = Settings.Default.MaxFindResultItems; + using var store = StateStore.Singleton.GetStoreSnapshot(); - var trie = new Trie(store, root_hash); - var contract = GetHistoricalContractState(trie, script_hash).NotNull_Or(RpcError.UnknownContract); - StorageKey pkey = new() + var trie = new Trie(store, rootHash); + var contract = GetHistoricalContractState(trie, scriptHash).NotNull_Or(RpcError.UnknownContract); + var pkey = new StorageKey() { Id = contract.Id, Key = prefix, }; - StorageKey fkey = new() + var fkey = new StorageKey() { Id = pkey.Id, Key = key, }; - JObject json = new(); - JArray jarr = new(); + + var json = new JObject(); + var jarr = new JArray(); int i = 0; foreach (var (ikey, ivalue) in trie.Find(pkey.ToArray(), 0 < key.Length ? fkey.ToArray() : null)) { if (count < i) break; if (i < count) { - JObject j = new(); - j["key"] = Convert.ToBase64String(ParseStorageKey(ikey.ToArray()).Key.Span); - j["value"] = Convert.ToBase64String(ivalue.Span); - jarr.Add(j); + jarr.Add(new JObject() + { + ["key"] = Convert.ToBase64String(ParseStorageKey(ikey.ToArray()).Key.Span), + ["value"] = Convert.ToBase64String(ivalue.Span), + }); } i++; } @@ -344,15 +366,16 @@ public JToken FindStates(JArray _params) [RpcMethod] public JToken GetState(JArray _params) { - var root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); - (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != root_hash).False_Or(RpcError.UnsupportedState); - var script_hash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); + var rootHash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != rootHash).False_Or(RpcError.UnsupportedState); + + var scriptHash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); var key = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[2]}")); using var store = StateStore.Singleton.GetStoreSnapshot(); - var trie = new Trie(store, root_hash); + var trie = new Trie(store, rootHash); - var contract = GetHistoricalContractState(trie, script_hash).NotNull_Or(RpcError.UnknownContract); - StorageKey skey = new() + var contract = GetHistoricalContractState(trie, scriptHash).NotNull_Or(RpcError.UnknownContract); + var skey = new StorageKey() { Id = contract.Id, Key = key, diff --git a/src/Plugins/StateService/Storage/StateSnapshot.cs b/src/Plugins/StateService/Storage/StateSnapshot.cs index 62f52e84b2..60af6f29ce 100644 --- a/src/Plugins/StateService/Storage/StateSnapshot.cs +++ b/src/Plugins/StateService/Storage/StateSnapshot.cs @@ -19,29 +19,29 @@ namespace Neo.Plugins.StateService.Storage { class StateSnapshot : IDisposable { - private readonly IStoreSnapshot snapshot; + private readonly IStoreSnapshot _snapshot; public Trie Trie; public StateSnapshot(IStore store) { - snapshot = store.GetSnapshot(); - Trie = new Trie(snapshot, CurrentLocalRootHash(), Settings.Default.FullState); + _snapshot = store.GetSnapshot(); + Trie = new Trie(_snapshot, CurrentLocalRootHash(), Settings.Default.FullState); } public StateRoot GetStateRoot(uint index) { - return snapshot.TryGet(Keys.StateRoot(index), out var data) ? data.AsSerializable() : null; + return _snapshot.TryGet(Keys.StateRoot(index), out var data) ? data.AsSerializable() : null; } - public void AddLocalStateRoot(StateRoot state_root) + public void AddLocalStateRoot(StateRoot stateRoot) { - snapshot.Put(Keys.StateRoot(state_root.Index), state_root.ToArray()); - snapshot.Put(Keys.CurrentLocalRootIndex, BitConverter.GetBytes(state_root.Index)); + _snapshot.Put(Keys.StateRoot(stateRoot.Index), stateRoot.ToArray()); + _snapshot.Put(Keys.CurrentLocalRootIndex, BitConverter.GetBytes(stateRoot.Index)); } public uint? CurrentLocalRootIndex() { - if (snapshot.TryGet(Keys.CurrentLocalRootIndex, out var bytes)) + if (_snapshot.TryGet(Keys.CurrentLocalRootIndex, out var bytes)) return BitConverter.ToUInt32(bytes); return null; } @@ -53,17 +53,17 @@ public UInt256 CurrentLocalRootHash() return GetStateRoot((uint)index)?.RootHash; } - public void AddValidatedStateRoot(StateRoot state_root) + public void AddValidatedStateRoot(StateRoot stateRoot) { - if (state_root?.Witness is null) - throw new ArgumentException(nameof(state_root) + " missing witness in invalidated state root"); - snapshot.Put(Keys.StateRoot(state_root.Index), state_root.ToArray()); - snapshot.Put(Keys.CurrentValidatedRootIndex, BitConverter.GetBytes(state_root.Index)); + if (stateRoot.Witness is null) + throw new ArgumentException(nameof(stateRoot) + " missing witness in invalidated state root"); + _snapshot.Put(Keys.StateRoot(stateRoot.Index), stateRoot.ToArray()); + _snapshot.Put(Keys.CurrentValidatedRootIndex, BitConverter.GetBytes(stateRoot.Index)); } public uint? CurrentValidatedRootIndex() { - if (snapshot.TryGet(Keys.CurrentValidatedRootIndex, out var bytes)) + if (_snapshot.TryGet(Keys.CurrentValidatedRootIndex, out var bytes)) return BitConverter.ToUInt32(bytes); return null; } @@ -72,21 +72,21 @@ public UInt256 CurrentValidatedRootHash() { var index = CurrentLocalRootIndex(); if (index is null) return null; - var state_root = GetStateRoot((uint)index); - if (state_root is null || state_root.Witness is null) + var stateRoot = GetStateRoot((uint)index); + if (stateRoot is null || stateRoot.Witness is null) throw new InvalidOperationException(nameof(CurrentValidatedRootHash) + " could not get validated state root"); - return state_root.RootHash; + return stateRoot.RootHash; } public void Commit() { Trie.Commit(); - snapshot.Commit(); + _snapshot.Commit(); } public void Dispose() { - snapshot.Dispose(); + _snapshot.Dispose(); } } } diff --git a/src/Plugins/StateService/Storage/StateStore.cs b/src/Plugins/StateService/Storage/StateStore.cs index 6c0560f47b..80968468b6 100644 --- a/src/Plugins/StateService/Storage/StateStore.cs +++ b/src/Plugins/StateService/Storage/StateStore.cs @@ -27,15 +27,15 @@ namespace Neo.Plugins.StateService.Storage { class StateStore : UntypedActor { - private readonly StatePlugin system; - private readonly IStore store; + private readonly StatePlugin _system; + private readonly IStore _store; private const int MaxCacheCount = 100; - private readonly Dictionary cache = []; - private StateSnapshot currentSnapshot; - private StateSnapshot? _state_snapshot; - public UInt256 CurrentLocalRootHash => currentSnapshot.CurrentLocalRootHash(); - public uint? LocalRootIndex => currentSnapshot.CurrentLocalRootIndex(); - public uint? ValidatedRootIndex => currentSnapshot.CurrentValidatedRootIndex(); + private readonly Dictionary _cache = []; + private StateSnapshot _currentSnapshot; + private StateSnapshot? _stateSnapshot; + public UInt256 CurrentLocalRootHash => _currentSnapshot.CurrentLocalRootHash(); + public uint? LocalRootIndex => _currentSnapshot.CurrentLocalRootIndex(); + public uint? ValidatedRootIndex => _currentSnapshot.CurrentValidatedRootIndex(); private static StateStore? _singleton; public static StateStore Singleton @@ -50,26 +50,26 @@ public static StateStore Singleton public StateStore(StatePlugin system, string path) { if (_singleton != null) throw new InvalidOperationException(nameof(StateStore)); - this.system = system; - store = StatePlugin._system.LoadStore(path); + _system = system; + _store = StatePlugin.NeoSystem.LoadStore(path); _singleton = this; - StatePlugin._system.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); - currentSnapshot = GetSnapshot(); + StatePlugin.NeoSystem.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + _currentSnapshot = GetSnapshot(); } public void Dispose() { - store.Dispose(); + _store.Dispose(); } public StateSnapshot GetSnapshot() { - return new StateSnapshot(store); + return new StateSnapshot(_store); } public IStoreSnapshot GetStoreSnapshot() { - return store.GetSnapshot(); + return _store.GetSnapshot(); } protected override void OnReceive(object message) @@ -92,6 +92,7 @@ private void OnStatePayload(ExtensiblePayload payload) { if (payload.Data.Length == 0) return; if ((MessageType)payload.Data.Span[0] != MessageType.StateRoot) return; + StateRoot message; try { @@ -104,89 +105,92 @@ private void OnStatePayload(ExtensiblePayload payload) OnNewStateRoot(message); } - private bool OnNewStateRoot(StateRoot state_root) + private bool OnNewStateRoot(StateRoot stateRoot) { - if (state_root?.Witness is null) return false; - if (ValidatedRootIndex != null && state_root.Index <= ValidatedRootIndex) return false; + if (stateRoot.Witness is null) return false; + if (ValidatedRootIndex != null && stateRoot.Index <= ValidatedRootIndex) return false; if (LocalRootIndex is null) throw new InvalidOperationException(nameof(StateStore) + " could not get local root index"); - if (LocalRootIndex < state_root.Index && state_root.Index < LocalRootIndex + MaxCacheCount) + if (LocalRootIndex < stateRoot.Index && stateRoot.Index < LocalRootIndex + MaxCacheCount) { - cache.Add(state_root.Index, state_root); + _cache.Add(stateRoot.Index, stateRoot); return true; } - using var state_snapshot = Singleton.GetSnapshot(); - var local_root = state_snapshot.GetStateRoot(state_root.Index); - if (local_root is null || local_root.Witness != null) return false; - if (!state_root.Verify(StatePlugin._system.Settings, StatePlugin._system.StoreView)) return false; - if (local_root.RootHash != state_root.RootHash) return false; - state_snapshot.AddValidatedStateRoot(state_root); - state_snapshot.Commit(); + + using var stateSnapshot = Singleton.GetSnapshot(); + var localRoot = stateSnapshot.GetStateRoot(stateRoot.Index); + if (localRoot is null || localRoot.Witness != null) return false; + if (!stateRoot.Verify(StatePlugin.NeoSystem.Settings, StatePlugin.NeoSystem.StoreView)) return false; + if (localRoot.RootHash != stateRoot.RootHash) return false; + + stateSnapshot.AddValidatedStateRoot(stateRoot); + stateSnapshot.Commit(); UpdateCurrentSnapshot(); - system.Verifier?.Tell(new VerificationService.ValidatedRootPersisted { Index = state_root.Index }); + _system.Verifier?.Tell(new VerificationService.ValidatedRootPersisted { Index = stateRoot.Index }); return true; } - public void UpdateLocalStateRootSnapshot(uint height, IEnumerable> change_set) + public void UpdateLocalStateRootSnapshot(uint height, IEnumerable> changeSet) { - _state_snapshot?.Dispose(); - _state_snapshot = Singleton.GetSnapshot(); - foreach (var item in change_set) + _stateSnapshot?.Dispose(); + _stateSnapshot = Singleton.GetSnapshot(); + foreach (var item in changeSet) { switch (item.Value.State) { case TrackState.Added: - _state_snapshot.Trie.Put(item.Key.ToArray(), item.Value.Item.ToArray()); + _stateSnapshot.Trie.Put(item.Key.ToArray(), item.Value.Item.ToArray()); break; case TrackState.Changed: - _state_snapshot.Trie.Put(item.Key.ToArray(), item.Value.Item.ToArray()); + _stateSnapshot.Trie.Put(item.Key.ToArray(), item.Value.Item.ToArray()); break; case TrackState.Deleted: - _state_snapshot.Trie.Delete(item.Key.ToArray()); + _stateSnapshot.Trie.Delete(item.Key.ToArray()); break; } } - var root_hash = _state_snapshot.Trie.Root.Hash; - var state_root = new StateRoot + + var rootHash = _stateSnapshot.Trie.Root.Hash; + var stateRoot = new StateRoot { Version = StateRoot.CurrentVersion, Index = height, - RootHash = root_hash, + RootHash = rootHash, Witness = null, }; - _state_snapshot.AddLocalStateRoot(state_root); + _stateSnapshot.AddLocalStateRoot(stateRoot); } public void UpdateLocalStateRoot(uint height) { - if (_state_snapshot != null) + if (_stateSnapshot != null) { - _state_snapshot.Commit(); - _state_snapshot.Dispose(); - _state_snapshot = null; + _stateSnapshot.Commit(); + _stateSnapshot.Dispose(); + _stateSnapshot = null; } UpdateCurrentSnapshot(); - system.Verifier?.Tell(new VerificationService.BlockPersisted { Index = height }); + _system.Verifier?.Tell(new VerificationService.BlockPersisted { Index = height }); CheckValidatedStateRoot(height); } private void CheckValidatedStateRoot(uint index) { - if (cache.TryGetValue(index, out var state_root)) + if (_cache.TryGetValue(index, out var stateRoot)) { - cache.Remove(index); - Self.Tell(state_root); + _cache.Remove(index); + Self.Tell(stateRoot); } } private void UpdateCurrentSnapshot() { - Interlocked.Exchange(ref currentSnapshot, GetSnapshot())?.Dispose(); + Interlocked.Exchange(ref _currentSnapshot, GetSnapshot())?.Dispose(); } protected override void PostStop() { - currentSnapshot?.Dispose(); - store?.Dispose(); + _currentSnapshot?.Dispose(); + _store?.Dispose(); base.PostStop(); } diff --git a/src/Plugins/StateService/Verification/VerificationContext.cs b/src/Plugins/StateService/Verification/VerificationContext.cs index aa4e626527..aa7d6db920 100644 --- a/src/Plugins/StateService/Verification/VerificationContext.cs +++ b/src/Plugins/StateService/Verification/VerificationContext.cs @@ -44,6 +44,7 @@ class VerificationContext public int MyIndex => myIndex; public uint RootIndex => rootIndex; public ECPoint[] Verifiers => verifiers; + public int Sender { get @@ -52,8 +53,10 @@ public int Sender return p >= 0 ? p : p + verifiers.Length; } } + public bool IsSender => myIndex == Sender; public ICancelable Timer; + public StateRoot StateRoot { get @@ -66,7 +69,9 @@ public StateRoot StateRoot return root; } } + public ExtensiblePayload StateRootMessage => rootPayload; + public ExtensiblePayload VoteMessage { get @@ -83,7 +88,7 @@ public VerificationContext(Wallet wallet, uint index) Retries = 0; myIndex = -1; rootIndex = index; - verifiers = NativeContract.RoleManagement.GetDesignatedByRole(StatePlugin._system.StoreView, Role.StateValidator, index); + verifiers = NativeContract.RoleManagement.GetDesignatedByRole(StatePlugin.NeoSystem.StoreView, Role.StateValidator, index); if (wallet is null) return; for (int i = 0; i < verifiers.Length; i++) { @@ -98,9 +103,9 @@ public VerificationContext(Wallet wallet, uint index) private ExtensiblePayload CreateVoteMessage() { if (StateRoot is null) return null; - if (!signatures.TryGetValue(myIndex, out byte[] sig)) + if (!signatures.TryGetValue(myIndex, out var sig)) { - sig = StateRoot.Sign(keyPair, StatePlugin._system.Settings.Network); + sig = StateRoot.Sign(keyPair, StatePlugin.NeoSystem.Settings.Network); signatures[myIndex] = sig; } return CreatePayload(MessageType.Vote, new Vote @@ -116,10 +121,12 @@ public bool AddSignature(int index, byte[] sig) if (M <= signatures.Count) return false; if (index < 0 || verifiers.Length <= index) return false; if (signatures.ContainsKey(index)) return false; + Utility.Log(nameof(VerificationContext), LogLevel.Info, $"vote received, height={rootIndex}, index={index}"); - ECPoint validator = verifiers[index]; - byte[] hash_data = StateRoot?.GetSignData(StatePlugin._system.Settings.Network); - if (hash_data is null || !Crypto.VerifySignature(hash_data, sig, validator)) + + var validator = verifiers[index]; + var hashData = StateRoot?.GetSignData(StatePlugin.NeoSystem.Settings.Network); + if (hashData is null || !Crypto.VerifySignature(hashData, sig, validator)) { Utility.Log(nameof(VerificationContext), LogLevel.Info, "incorrect vote, invalid signature"); return false; @@ -133,8 +140,8 @@ public bool CheckSignatures() if (signatures.Count < M) return false; if (StateRoot.Witness is null) { - Contract contract = Contract.CreateMultiSigContract(M, verifiers); - ContractParametersContext sc = new(StatePlugin._system.StoreView, StateRoot, StatePlugin._system.Settings.Network); + var contract = Contract.CreateMultiSigContract(M, verifiers); + var sc = new ContractParametersContext(StatePlugin.NeoSystem.StoreView, StateRoot, StatePlugin.NeoSystem.Settings.Network); for (int i = 0, j = 0; i < verifiers.Length && j < M; i++) { if (!signatures.TryGetValue(i, out byte[] sig)) continue; @@ -152,15 +159,16 @@ public bool CheckSignatures() private ExtensiblePayload CreatePayload(MessageType type, ISerializable payload, uint validBlockEndThreshold) { byte[] data; - using (MemoryStream ms = new MemoryStream()) - using (BinaryWriter writer = new BinaryWriter(ms)) + using (var ms = new MemoryStream()) + using (var writer = new BinaryWriter(ms)) { writer.Write((byte)type); payload.Serialize(writer); writer.Flush(); data = ms.ToArray(); } - ExtensiblePayload msg = new ExtensiblePayload + + var msg = new ExtensiblePayload { Category = StatePlugin.StatePayloadCategory, ValidBlockStart = StateRoot.Index, @@ -168,7 +176,8 @@ private ExtensiblePayload CreatePayload(MessageType type, ISerializable payload, Sender = Contract.CreateSignatureRedeemScript(verifiers[MyIndex]).ToScriptHash(), Data = data, }; - ContractParametersContext sc = new ContractParametersContext(StatePlugin._system.StoreView, msg, StatePlugin._system.Settings.Network); + + var sc = new ContractParametersContext(StatePlugin.NeoSystem.StoreView, msg, StatePlugin.NeoSystem.Settings.Network); wallet.Sign(sc); msg.Witness = sc.GetWitnesses()[0]; return msg; diff --git a/src/Plugins/StateService/Verification/VerificationService.cs b/src/Plugins/StateService/Verification/VerificationService.cs index a4f36e8f9b..c35cfaba70 100644 --- a/src/Plugins/StateService/Verification/VerificationService.cs +++ b/src/Plugins/StateService/Verification/VerificationService.cs @@ -30,24 +30,24 @@ public class BlockPersisted { public uint Index; } private class Timer { public uint Index; } private static readonly uint DelayMilliseconds = 3000; private readonly Wallet wallet; - private readonly ConcurrentDictionary contexts = new ConcurrentDictionary(); + private readonly ConcurrentDictionary contexts = new(); public VerificationService(Wallet wallet) { this.wallet = wallet; - StatePlugin._system.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + StatePlugin.NeoSystem.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); } private void SendVote(VerificationContext context) { if (context.VoteMessage is null) return; Utility.Log(nameof(VerificationService), LogLevel.Info, $"relay vote, height={context.RootIndex}, retry={context.Retries}"); - StatePlugin._system.Blockchain.Tell(context.VoteMessage); + StatePlugin.NeoSystem.Blockchain.Tell(context.VoteMessage); } private void OnStateRootVote(Vote vote) { - if (contexts.TryGetValue(vote.RootIndex, out VerificationContext context) && context.AddSignature(vote.ValidatorIndex, vote.Signature.ToArray())) + if (contexts.TryGetValue(vote.RootIndex, out var context) && context.AddSignature(vote.ValidatorIndex, vote.Signature.ToArray())) { CheckVotes(context); } @@ -59,7 +59,7 @@ private void CheckVotes(VerificationContext context) { if (context.StateRootMessage is null) return; Utility.Log(nameof(VerificationService), LogLevel.Info, $"relay state root, height={context.StateRoot.Index}, root={context.StateRoot.RootHash}"); - StatePlugin._system.Blockchain.Tell(context.StateRootMessage); + StatePlugin.NeoSystem.Blockchain.Tell(context.StateRootMessage); } } @@ -105,10 +105,11 @@ private void OnTimer(uint index) SendVote(context); CheckVotes(context); context.Timer.CancelIfNotNull(); - context.Timer = Context.System.Scheduler.ScheduleTellOnceCancelable(TimeSpan.FromMilliseconds((uint)StatePlugin._system.GetTimePerBlock().TotalMilliseconds << context.Retries), Self, new Timer - { - Index = index, - }, ActorRefs.NoSender); + context.Timer = Context.System.Scheduler.ScheduleTellOnceCancelable( + TimeSpan.FromMilliseconds((uint)StatePlugin.NeoSystem.GetTimePerBlock().TotalMilliseconds << context.Retries), + Self, + new Timer { Index = index, }, + ActorRefs.NoSender); context.Retries++; } } @@ -117,6 +118,7 @@ private void OnVoteMessage(ExtensiblePayload payload) { if (payload.Data.Length == 0) return; if ((MessageType)payload.Data.Span[0] != MessageType.Vote) return; + Vote message; try {