Skip to content

Commit d00d90b

Browse files
authored
init (#790)
1 parent f3aa665 commit d00d90b

File tree

5 files changed

+260
-1
lines changed

5 files changed

+260
-1
lines changed

neo-modules.sln

+8-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPTTrie", "src\MPTTrie\MPTT
3939
EndProject
4040
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}"
4141
EndProject
42-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteWallet", "src\SQLiteWallet\SQLiteWallet.csproj", "{D121D57A-512E-4F74-ADA1-24482BF5C42B}"
42+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteWallet", "src\SQLiteWallet\SQLiteWallet.csproj", "{D121D57A-512E-4F74-ADA1-24482BF5C42B}"
43+
EndProject
44+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageDumper", "src\StorageDumper\StorageDumper.csproj", "{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}"
4345
EndProject
4446
Global
4547
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -115,6 +117,10 @@ Global
115117
{D121D57A-512E-4F74-ADA1-24482BF5C42B}.Debug|Any CPU.Build.0 = Debug|Any CPU
116118
{D121D57A-512E-4F74-ADA1-24482BF5C42B}.Release|Any CPU.ActiveCfg = Release|Any CPU
117119
{D121D57A-512E-4F74-ADA1-24482BF5C42B}.Release|Any CPU.Build.0 = Release|Any CPU
120+
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
121+
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
122+
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
123+
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC}.Release|Any CPU.Build.0 = Release|Any CPU
118124
EndGlobalSection
119125
GlobalSection(SolutionProperties) = preSolution
120126
HideSolutionNode = FALSE
@@ -137,6 +143,7 @@ Global
137143
{D167FA6B-D2A3-4D8A-A65D-686DD06650F6} = {97E81C78-1637-481F-9485-DA1225E94C23}
138144
{8D2EE375-2E2D-45FE-A4E9-0254D12C7554} = {59D802AB-C552-422A-B9C3-64D329FBCDCC}
139145
{D121D57A-512E-4F74-ADA1-24482BF5C42B} = {97E81C78-1637-481F-9485-DA1225E94C23}
146+
{938D86EA-0F48-436B-9255-4AD9A8E6B9AC} = {97E81C78-1637-481F-9485-DA1225E94C23}
140147
EndGlobalSection
141148
GlobalSection(ExtensibilityGlobals) = postSolution
142149
SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3}

src/StorageDumper/Settings.cs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (C) 2015-2023 The Neo Project.
2+
//
3+
// The Neo.Plugins.StatesDumper is free software distributed under the MIT software license,
4+
// see the accompanying file LICENSE in the main directory of the
5+
// project or http://www.opensource.org/licenses/mit-license.php
6+
// for more details.
7+
//
8+
// Redistribution and use in source and binary forms with or without
9+
// modifications are permitted.
10+
11+
using Microsoft.Extensions.Configuration;
12+
using Neo.SmartContract.Native;
13+
using System.Collections.Generic;
14+
using System.Linq;
15+
16+
namespace Neo.Plugins
17+
{
18+
internal class Settings
19+
{
20+
/// <summary>
21+
/// Amount of storages states (heights) to be dump in a given json file
22+
/// </summary>
23+
public uint BlockCacheSize { get; }
24+
/// <summary>
25+
/// Height to begin storage dump
26+
/// </summary>
27+
public uint HeightToBegin { get; }
28+
29+
public IReadOnlyList<int> Exclude { get; }
30+
31+
public static Settings Default { get; private set; }
32+
33+
private Settings(IConfigurationSection section)
34+
{
35+
/// Geting settings for storage changes state dumper
36+
this.BlockCacheSize = section.GetValue("BlockCacheSize", 1000u);
37+
this.HeightToBegin = section.GetValue("HeightToBegin", 0u);
38+
this.Exclude = section.GetSection("Exclude").Exists()
39+
? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray()
40+
: new[] { NativeContract.Ledger.Id };
41+
}
42+
43+
public static void Load(IConfigurationSection section)
44+
{
45+
Default = new Settings(section);
46+
}
47+
}
48+
}

src/StorageDumper/StorageDumper.cs

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
// Copyright (C) 2015-2023 The Neo Project.
2+
//
3+
// The Neo.Plugins.StatesDumper is free software distributed under the MIT software license,
4+
// see the accompanying file LICENSE in the main directory of the
5+
// project or http://www.opensource.org/licenses/mit-license.php
6+
// for more details.
7+
//
8+
// Redistribution and use in source and binary forms with or without
9+
// modifications are permitted.
10+
11+
using Neo.ConsoleService;
12+
using Neo.IO;
13+
using Neo.Json;
14+
using Neo.Ledger;
15+
using Neo.Network.P2P.Payloads;
16+
using Neo.Persistence;
17+
using Neo.SmartContract.Native;
18+
using System;
19+
using System.Collections.Generic;
20+
using System.IO;
21+
using System.Linq;
22+
23+
namespace Neo.Plugins
24+
{
25+
public class StorageDumper : Plugin
26+
{
27+
private readonly Dictionary<uint, NeoSystem> systems = new Dictionary<uint, NeoSystem>();
28+
29+
private StreamWriter _writer;
30+
private JObject _currentBlock;
31+
private string _lastCreateDirectory;
32+
33+
34+
public override string Description => "Exports Neo-CLI status data";
35+
36+
public StorageDumper()
37+
{
38+
Blockchain.Committing += OnCommitting;
39+
Blockchain.Committed += OnCommitted;
40+
}
41+
42+
public override void Dispose()
43+
{
44+
Blockchain.Committing -= OnCommitting;
45+
Blockchain.Committed -= OnCommitted;
46+
}
47+
48+
protected override void Configure()
49+
{
50+
Settings.Load(GetConfiguration());
51+
}
52+
53+
protected override void OnSystemLoaded(NeoSystem system)
54+
{
55+
systems.Add(system.Settings.Network, system);
56+
}
57+
58+
/// <summary>
59+
/// Process "dump contract-storage" command
60+
/// </summary>
61+
[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")]
62+
private void OnDumpStorage(uint network, UInt160 contractHash = null)
63+
{
64+
if (!systems.ContainsKey(network)) throw new InvalidOperationException("invalid network");
65+
string path = $"dump_{network}.json";
66+
byte[] prefix = null;
67+
if (contractHash is not null)
68+
{
69+
var contract = NativeContract.ContractManagement.GetContract(systems[network].StoreView, contractHash);
70+
if (contract is null) throw new InvalidOperationException("contract not found");
71+
prefix = BitConverter.GetBytes(contract.Id);
72+
}
73+
var states = systems[network].StoreView.Find(prefix);
74+
JArray array = new JArray(states.Where(p => !Settings.Default.Exclude.Contains(p.Key.Id)).Select(p => new JObject
75+
{
76+
["key"] = Convert.ToBase64String(p.Key.ToArray()),
77+
["value"] = Convert.ToBase64String(p.Value.ToArray())
78+
}));
79+
File.WriteAllText(path, array.ToString());
80+
ConsoleHelper.Info("States",
81+
$"({array.Count})",
82+
" have been dumped into file ",
83+
$"{path}");
84+
}
85+
86+
private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList<Blockchain.ApplicationExecuted> applicationExecutedList)
87+
{
88+
InitFileWriter(system.Settings.Network, snapshot);
89+
OnPersistStorage(system.Settings.Network, snapshot);
90+
}
91+
92+
private void OnPersistStorage(uint network, DataCache snapshot)
93+
{
94+
uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot);
95+
if (blockIndex >= Settings.Default.HeightToBegin)
96+
{
97+
JArray array = new JArray();
98+
99+
foreach (var trackable in snapshot.GetChangeSet())
100+
{
101+
if (Settings.Default.Exclude.Contains(trackable.Key.Id))
102+
continue;
103+
JObject state = new JObject();
104+
switch (trackable.State)
105+
{
106+
case TrackState.Added:
107+
state["state"] = "Added";
108+
state["key"] = Convert.ToBase64String(trackable.Key.ToArray());
109+
state["value"] = Convert.ToBase64String(trackable.Item.ToArray());
110+
// Here we have a new trackable.Key and trackable.Item
111+
break;
112+
case TrackState.Changed:
113+
state["state"] = "Changed";
114+
state["key"] = Convert.ToBase64String(trackable.Key.ToArray());
115+
state["value"] = Convert.ToBase64String(trackable.Item.ToArray());
116+
break;
117+
case TrackState.Deleted:
118+
state["state"] = "Deleted";
119+
state["key"] = Convert.ToBase64String(trackable.Key.ToArray());
120+
break;
121+
}
122+
array.Add(state);
123+
}
124+
125+
JObject bs_item = new JObject();
126+
bs_item["block"] = blockIndex;
127+
bs_item["size"] = array.Count;
128+
bs_item["storage"] = array;
129+
_currentBlock = bs_item;
130+
}
131+
}
132+
133+
134+
private void OnCommitted(NeoSystem system, Block block)
135+
{
136+
OnCommitStorage(system.Settings.Network, system.StoreView);
137+
}
138+
139+
void OnCommitStorage(uint network, DataCache snapshot)
140+
{
141+
if (_currentBlock != null)
142+
{
143+
_writer.WriteLine(_currentBlock.ToString());
144+
_writer.Flush();
145+
}
146+
}
147+
148+
private void InitFileWriter(uint network, DataCache snapshot)
149+
{
150+
uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot);
151+
if (_writer == null
152+
|| blockIndex % Settings.Default.BlockCacheSize == 0)
153+
{
154+
string path = GetOrCreateDirectory(network, blockIndex);
155+
var filepart = (blockIndex / Settings.Default.BlockCacheSize) * Settings.Default.BlockCacheSize;
156+
path = $"{path}/dump-block-{filepart}.dump";
157+
if (_writer != null)
158+
{
159+
_writer.Dispose();
160+
}
161+
_writer = new StreamWriter(new FileStream(path, FileMode.Append));
162+
}
163+
}
164+
165+
private string GetOrCreateDirectory(uint network, uint blockIndex)
166+
{
167+
string dirPathWithBlock = GetDirectoryPath(network, blockIndex);
168+
if (_lastCreateDirectory != dirPathWithBlock)
169+
{
170+
Directory.CreateDirectory(dirPathWithBlock);
171+
_lastCreateDirectory = dirPathWithBlock;
172+
}
173+
return dirPathWithBlock;
174+
}
175+
176+
private string GetDirectoryPath(uint network, uint blockIndex)
177+
{
178+
//Default Parameter
179+
uint storagePerFolder = 100000;
180+
uint folder = (blockIndex / storagePerFolder) * storagePerFolder;
181+
return $"./StorageDumper_{network}/BlockStorage_{folder}";
182+
}
183+
184+
}
185+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<PackageId>Neo.Plugins.StorageDumper</PackageId>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Neo.ConsoleService" Version="1.2.0" />
11+
</ItemGroup>
12+
</Project>

src/StorageDumper/config.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"PluginConfiguration": {
3+
"BlockCacheSize": 1000,
4+
"HeightToBegin": 0,
5+
"Exclude": [ -4 ]
6+
}
7+
}

0 commit comments

Comments
 (0)