Skip to content

Commit

Permalink
init (#790)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashuaidehao authored Jan 20, 2023
1 parent f3aa665 commit d00d90b
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 1 deletion.
9 changes: 8 additions & 1 deletion neo-modules.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPTTrie", "src\MPTTrie\MPTT
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.MPTTrie.Tests", "tests\Neo.Cryptography.MPTTrie.Tests\Neo.Cryptography.MPTTrie.Tests.csproj", "{8D2EE375-2E2D-45FE-A4E9-0254D12C7554}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteWallet", "src\SQLiteWallet\SQLiteWallet.csproj", "{D121D57A-512E-4F74-ADA1-24482BF5C42B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteWallet", "src\SQLiteWallet\SQLiteWallet.csproj", "{D121D57A-512E-4F74-ADA1-24482BF5C42B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageDumper", "src\StorageDumper\StorageDumper.csproj", "{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -115,6 +117,10 @@ Global
{D121D57A-512E-4F74-ADA1-24482BF5C42B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D121D57A-512E-4F74-ADA1-24482BF5C42B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D121D57A-512E-4F74-ADA1-24482BF5C42B}.Release|Any CPU.Build.0 = Release|Any CPU
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -137,6 +143,7 @@ Global
{D167FA6B-D2A3-4D8A-A65D-686DD06650F6} = {97E81C78-1637-481F-9485-DA1225E94C23}
{8D2EE375-2E2D-45FE-A4E9-0254D12C7554} = {59D802AB-C552-422A-B9C3-64D329FBCDCC}
{D121D57A-512E-4F74-ADA1-24482BF5C42B} = {97E81C78-1637-481F-9485-DA1225E94C23}
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC} = {97E81C78-1637-481F-9485-DA1225E94C23}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3}
Expand Down
48 changes: 48 additions & 0 deletions src/StorageDumper/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (C) 2015-2023 The Neo Project.
//
// The Neo.Plugins.StatesDumper is free software distributed under the MIT software license,
// see the accompanying file LICENSE in the main directory of the
// project or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Microsoft.Extensions.Configuration;
using Neo.SmartContract.Native;
using System.Collections.Generic;
using System.Linq;

namespace Neo.Plugins
{
internal class Settings
{
/// <summary>
/// Amount of storages states (heights) to be dump in a given json file
/// </summary>
public uint BlockCacheSize { get; }
/// <summary>
/// Height to begin storage dump
/// </summary>
public uint HeightToBegin { get; }

public IReadOnlyList<int> Exclude { get; }

public static Settings Default { get; private set; }

private Settings(IConfigurationSection section)
{
/// Geting settings for storage changes state dumper
this.BlockCacheSize = section.GetValue("BlockCacheSize", 1000u);
this.HeightToBegin = section.GetValue("HeightToBegin", 0u);
this.Exclude = section.GetSection("Exclude").Exists()
? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray()
: new[] { NativeContract.Ledger.Id };
}

public static void Load(IConfigurationSection section)
{
Default = new Settings(section);
}
}
}
185 changes: 185 additions & 0 deletions src/StorageDumper/StorageDumper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright (C) 2015-2023 The Neo Project.
//
// The Neo.Plugins.StatesDumper is free software distributed under the MIT software license,
// see the accompanying file LICENSE in the main directory of the
// project or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.ConsoleService;
using Neo.IO;
using Neo.Json;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract.Native;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Neo.Plugins
{
public class StorageDumper : Plugin
{
private readonly Dictionary<uint, NeoSystem> systems = new Dictionary<uint, NeoSystem>();

private StreamWriter _writer;
private JObject _currentBlock;
private string _lastCreateDirectory;


public override string Description => "Exports Neo-CLI status data";

public StorageDumper()
{
Blockchain.Committing += OnCommitting;
Blockchain.Committed += OnCommitted;
}

public override void Dispose()
{
Blockchain.Committing -= OnCommitting;
Blockchain.Committed -= OnCommitted;
}

protected override void Configure()
{
Settings.Load(GetConfiguration());
}

protected override void OnSystemLoaded(NeoSystem system)
{
systems.Add(system.Settings.Network, system);
}

/// <summary>
/// Process "dump contract-storage" command
/// </summary>
[ConsoleCommand("dump contract-storage", Category = "Storage", Description = "You can specify the contract script hash or use null to get the corresponding information from the storage")]
private void OnDumpStorage(uint network, UInt160 contractHash = null)
{
if (!systems.ContainsKey(network)) throw new InvalidOperationException("invalid network");
string path = $"dump_{network}.json";
byte[] prefix = null;
if (contractHash is not null)
{
var contract = NativeContract.ContractManagement.GetContract(systems[network].StoreView, contractHash);
if (contract is null) throw new InvalidOperationException("contract not found");
prefix = BitConverter.GetBytes(contract.Id);
}
var states = systems[network].StoreView.Find(prefix);
JArray array = new JArray(states.Where(p => !Settings.Default.Exclude.Contains(p.Key.Id)).Select(p => new JObject
{
["key"] = Convert.ToBase64String(p.Key.ToArray()),
["value"] = Convert.ToBase64String(p.Value.ToArray())
}));
File.WriteAllText(path, array.ToString());
ConsoleHelper.Info("States",
$"({array.Count})",
" have been dumped into file ",
$"{path}");
}

private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList<Blockchain.ApplicationExecuted> applicationExecutedList)
{
InitFileWriter(system.Settings.Network, snapshot);
OnPersistStorage(system.Settings.Network, snapshot);
}

private void OnPersistStorage(uint network, DataCache snapshot)
{
uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot);
if (blockIndex >= Settings.Default.HeightToBegin)
{
JArray array = new JArray();

foreach (var trackable in snapshot.GetChangeSet())
{
if (Settings.Default.Exclude.Contains(trackable.Key.Id))
continue;
JObject state = new JObject();
switch (trackable.State)
{
case TrackState.Added:
state["state"] = "Added";
state["key"] = Convert.ToBase64String(trackable.Key.ToArray());
state["value"] = Convert.ToBase64String(trackable.Item.ToArray());
// Here we have a new trackable.Key and trackable.Item
break;
case TrackState.Changed:
state["state"] = "Changed";
state["key"] = Convert.ToBase64String(trackable.Key.ToArray());
state["value"] = Convert.ToBase64String(trackable.Item.ToArray());
break;
case TrackState.Deleted:
state["state"] = "Deleted";
state["key"] = Convert.ToBase64String(trackable.Key.ToArray());
break;
}
array.Add(state);
}

JObject bs_item = new JObject();
bs_item["block"] = blockIndex;
bs_item["size"] = array.Count;
bs_item["storage"] = array;
_currentBlock = bs_item;
}
}


private void OnCommitted(NeoSystem system, Block block)
{
OnCommitStorage(system.Settings.Network, system.StoreView);
}

void OnCommitStorage(uint network, DataCache snapshot)
{
if (_currentBlock != null)
{
_writer.WriteLine(_currentBlock.ToString());
_writer.Flush();
}
}

private void InitFileWriter(uint network, DataCache snapshot)
{
uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot);
if (_writer == null
|| blockIndex % Settings.Default.BlockCacheSize == 0)
{
string path = GetOrCreateDirectory(network, blockIndex);
var filepart = (blockIndex / Settings.Default.BlockCacheSize) * Settings.Default.BlockCacheSize;
path = $"{path}/dump-block-{filepart}.dump";
if (_writer != null)
{
_writer.Dispose();
}
_writer = new StreamWriter(new FileStream(path, FileMode.Append));
}
}

private string GetOrCreateDirectory(uint network, uint blockIndex)
{
string dirPathWithBlock = GetDirectoryPath(network, blockIndex);
if (_lastCreateDirectory != dirPathWithBlock)
{
Directory.CreateDirectory(dirPathWithBlock);
_lastCreateDirectory = dirPathWithBlock;
}
return dirPathWithBlock;
}

private string GetDirectoryPath(uint network, uint blockIndex)
{
//Default Parameter
uint storagePerFolder = 100000;
uint folder = (blockIndex / storagePerFolder) * storagePerFolder;
return $"./StorageDumper_{network}/BlockStorage_{folder}";
}

}
}
12 changes: 12 additions & 0 deletions src/StorageDumper/StorageDumper.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>Neo.Plugins.StorageDumper</PackageId>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Neo.ConsoleService" Version="1.2.0" />
</ItemGroup>
</Project>
7 changes: 7 additions & 0 deletions src/StorageDumper/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"PluginConfiguration": {
"BlockCacheSize": 1000,
"HeightToBegin": 0,
"Exclude": [ -4 ]
}
}

0 comments on commit d00d90b

Please sign in to comment.