Skip to content

Commit 5ba0d16

Browse files
committed
Init commit from ElementExplorer
1 parent a9490f3 commit 5ba0d16

30 files changed

+5884
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
9+
<PackageReference Include="xunit" Version="2.2.0" />
10+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta3-build3705" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\ElementsExplorer\ElementsExplorer.csproj" />
15+
<ProjectReference Include="..\NElements.TestFramework\NBitcoin.TestFramework.csproj" />
16+
<ProjectReference Include="..\NElements\NBitcoin.NETCore\NBitcoin.NETCore.csproj" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
21+
</ItemGroup>
22+
23+
</Project>
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
4+
using System.Text;
5+
6+
namespace ElementsExplorer.Tests
7+
{
8+
public class RepositoryTester : IDisposable
9+
{
10+
public static RepositoryTester Create(bool caching, [CallerMemberName]string name = null)
11+
{
12+
return new RepositoryTester(name, caching);
13+
}
14+
15+
string _Name;
16+
RepositoryTester(string name, bool caching)
17+
{
18+
_Name = name;
19+
ServerTester.DeleteRecursivelyWithMagicDust(name);
20+
_Repository = new Repository(name, caching);
21+
}
22+
23+
public void Dispose()
24+
{
25+
_Repository.Dispose();
26+
ServerTester.DeleteRecursivelyWithMagicDust(_Name);
27+
}
28+
29+
public void ReloadRepository(bool caching)
30+
{
31+
_Repository.Dispose();
32+
_Repository = new Repository(_Name, caching);
33+
}
34+
35+
private Repository _Repository;
36+
public Repository Repository
37+
{
38+
get
39+
{
40+
return _Repository;
41+
}
42+
}
43+
}
44+
}
+299
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
using System.Linq;
2+
using ElementsExplorer.Configuration;
3+
using Microsoft.AspNetCore.Hosting;
4+
using NBitcoin;
5+
using NBitcoin.Tests;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Diagnostics;
9+
using System.IO;
10+
using System.Runtime.CompilerServices;
11+
using System.Text;
12+
using System.Text.RegularExpressions;
13+
using System.Threading;
14+
using System.Threading.Tasks;
15+
using Microsoft.AspNetCore.Server.Kestrel;
16+
using Microsoft.AspNetCore.Hosting.Server;
17+
using Microsoft.AspNetCore.Hosting.Server.Features;
18+
19+
namespace ElementsExplorer.Tests
20+
{
21+
public class ServerTester : IDisposable
22+
{
23+
private readonly string _Directory;
24+
25+
public static ServerTester Create([CallerMemberNameAttribute]string caller = null)
26+
{
27+
return new ServerTester(caller);
28+
}
29+
30+
public void Dispose()
31+
{
32+
if(Host != null)
33+
{
34+
Host.Dispose();
35+
Host = null;
36+
}
37+
if(Runtime != null)
38+
{
39+
Runtime.Dispose();
40+
Runtime = null;
41+
}
42+
if(NodeBuilder != null)
43+
{
44+
NodeBuilder.Dispose();
45+
NodeBuilder = null;
46+
}
47+
}
48+
49+
public ServerTester(string directory)
50+
{
51+
try
52+
{
53+
54+
var rootTestData = "TestData";
55+
var cachedNodes = "TestData/CachedNodes";
56+
directory = rootTestData + "/" + directory;
57+
_Directory = directory;
58+
if(!Directory.Exists(rootTestData))
59+
Directory.CreateDirectory(rootTestData);
60+
if(!Directory.Exists(cachedNodes))
61+
{
62+
Directory.CreateDirectory(cachedNodes);
63+
RunScenario(cachedNodes);
64+
}
65+
66+
if(!TryDelete(directory, false))
67+
{
68+
foreach(var process in Process.GetProcessesByName("elementd"))
69+
{
70+
if(process.MainModule.FileName.Replace("\\", "/").StartsWith(Path.GetFullPath(rootTestData).Replace("\\", "/"), StringComparison.Ordinal))
71+
{
72+
process.Kill();
73+
process.WaitForExit();
74+
}
75+
}
76+
TryDelete(directory, true);
77+
}
78+
79+
NodeBuilder = NodeBuilder.Create(directory);
80+
NodeBuilder.CleanBeforeStartingNode = false;
81+
Copy(cachedNodes, directory);
82+
83+
84+
User1 = NodeBuilder.CreateNode();
85+
User2 = NodeBuilder.CreateNode();
86+
Explorer = NodeBuilder.CreateNode();
87+
NodeBuilder.StartAll();
88+
89+
var creds = ExtractCredentials(File.ReadAllText(Explorer.Config));
90+
var conf = new ExplorerConfiguration();
91+
conf.DataDir = Path.Combine(directory, "explorer");
92+
conf.Network = Network.RegTest;
93+
conf.RPC = new RPCArgs()
94+
{
95+
User = creds.Item1,
96+
Password = creds.Item2,
97+
Url = Explorer.CreateRPCClient().Address,
98+
NoTest = true
99+
};
100+
conf.NodeEndpoint = Explorer.Endpoint;
101+
conf.Network = ExplorerConfiguration.CreateNetwork(conf.Network, Explorer.CreateRPCClient().GetBlock(0));
102+
103+
Runtime = conf.CreateRuntime();
104+
105+
Runtime.Repository.SetIndexProgress(new BlockLocator() { Blocks = { Runtime.RPC.GetBestBlockHash() } });
106+
107+
Runtime.StartNodeListener(conf.StartHeight);
108+
Host = Runtime.CreateWebHost();
109+
Host.Start();
110+
}
111+
catch
112+
{
113+
Dispose();
114+
throw;
115+
}
116+
}
117+
118+
private void RunScenario(string directory)
119+
{
120+
NodeBuilder = NodeBuilder.Create(directory);
121+
User1 = NodeBuilder.CreateNode();
122+
User2 = NodeBuilder.CreateNode();
123+
Explorer = NodeBuilder.CreateNode();
124+
NodeBuilder.StartAll();
125+
User1.CreateRPCClient().Generate(1);
126+
Explorer.CreateRPCClient().Generate(1);
127+
User2.CreateRPCClient().Generate(101);
128+
User1.Sync(User2, true);
129+
Explorer.Sync(User1, true);
130+
var a = User1.CreateRPCClient().GetBlockCount();
131+
var b = User1.CreateRPCClient().GetBlockCount();
132+
var c = User1.CreateRPCClient().GetBlockCount();
133+
Task.WaitAll(new Task[]
134+
{
135+
User1.CreateRPCClient().SendCommandAsync("stop"),
136+
User2.CreateRPCClient().SendCommandAsync("stop"),
137+
Explorer.CreateRPCClient().SendCommandAsync("stop")
138+
}.ToArray());
139+
140+
User1.WaitForExit();
141+
User2.WaitForExit();
142+
Explorer.WaitForExit();
143+
NodeBuilder = null;
144+
}
145+
146+
private Tuple<string, string> ExtractCredentials(string config)
147+
{
148+
var user = Regex.Match(config, "rpcuser=([^\r\n]*)");
149+
var pass = Regex.Match(config, "rpcpassword=([^\r\n]*)");
150+
return Tuple.Create(user.Groups[1].Value, pass.Groups[1].Value);
151+
}
152+
153+
public Uri Address
154+
{
155+
get
156+
{
157+
158+
var address = ((KestrelServer)(Host.Services.GetService(typeof(IServer)))).Features.Get<IServerAddressesFeature>().Addresses.FirstOrDefault();
159+
return new Uri(address);
160+
}
161+
}
162+
163+
ExplorerClient _Client;
164+
public ExplorerClient Client
165+
{
166+
get
167+
{
168+
return _Client = _Client ?? new ExplorerClient(Runtime.Network, Address);
169+
}
170+
}
171+
172+
public CoreNode Explorer
173+
{
174+
get; set;
175+
}
176+
177+
public CoreNode User1
178+
{
179+
get; set;
180+
}
181+
182+
public CoreNode User2
183+
{
184+
get; set;
185+
}
186+
187+
public NodeBuilder NodeBuilder
188+
{
189+
get; set;
190+
}
191+
192+
public ExplorerRuntime Runtime
193+
{
194+
get; set;
195+
}
196+
197+
public IWebHost Host
198+
{
199+
get; set;
200+
}
201+
202+
public string BaseDirectory
203+
{
204+
get
205+
{
206+
return _Directory;
207+
}
208+
}
209+
210+
private static bool TryDelete(string directory, bool throws)
211+
{
212+
try
213+
{
214+
DeleteRecursivelyWithMagicDust(directory);
215+
return true;
216+
}
217+
catch(DirectoryNotFoundException)
218+
{
219+
return true;
220+
}
221+
catch(Exception)
222+
{
223+
if(throws)
224+
throw;
225+
}
226+
return false;
227+
}
228+
229+
// http://stackoverflow.com/a/14933880/2061103
230+
public static void DeleteRecursivelyWithMagicDust(string destinationDir)
231+
{
232+
const int magicDust = 10;
233+
for(var gnomes = 1; gnomes <= magicDust; gnomes++)
234+
{
235+
try
236+
{
237+
Directory.Delete(destinationDir, true);
238+
}
239+
catch(DirectoryNotFoundException)
240+
{
241+
return; // good!
242+
}
243+
catch(IOException)
244+
{
245+
if(gnomes == magicDust)
246+
throw;
247+
// System.IO.IOException: The directory is not empty
248+
System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);
249+
250+
// see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
251+
Thread.Sleep(100);
252+
continue;
253+
}
254+
catch(UnauthorizedAccessException)
255+
{
256+
if(gnomes == magicDust)
257+
throw;
258+
// Wait, maybe another software make us authorized a little later
259+
System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);
260+
261+
// see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
262+
Thread.Sleep(100);
263+
continue;
264+
}
265+
return;
266+
}
267+
// depending on your use case, consider throwing an exception here
268+
}
269+
270+
static void Copy(string sourceDirectory, string targetDirectory)
271+
{
272+
DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
273+
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);
274+
275+
CopyAll(diSource, diTarget);
276+
}
277+
278+
static void CopyAll(DirectoryInfo source, DirectoryInfo target)
279+
{
280+
Directory.CreateDirectory(target.FullName);
281+
282+
// Copy each file into the new directory.
283+
foreach(FileInfo fi in source.GetFiles())
284+
{
285+
Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
286+
fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
287+
}
288+
289+
// Copy each subdirectory using recursion.
290+
foreach(DirectoryInfo diSourceSubDir in source.GetDirectories())
291+
{
292+
DirectoryInfo nextTargetSubDir =
293+
target.CreateSubdirectory(diSourceSubDir.Name);
294+
CopyAll(diSourceSubDir, nextTargetSubDir);
295+
}
296+
}
297+
298+
}
299+
}

0 commit comments

Comments
 (0)