Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
destream-blockchain
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
2
Issues
2
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DeStream-public
destream-blockchain
Commits
80032683
Commit
80032683
authored
Aug 06, 2018
by
Pavel Pavlov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding transaction to block and adding block to chain (test)
parent
c6f578c0
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
133 additions
and
110 deletions
+133
-110
Program.cs
Sources/DeStream.DeStreamD.ForTest/Program.cs
+17
-97
TestClassHelper.cs
Sources/DeStream.DeStreamD.ForTest/TestClassHelper.cs
+116
-13
No files found.
Sources/DeStream.DeStreamD.ForTest/Program.cs
View file @
80032683
...
@@ -17,6 +17,7 @@ using Stratis.Bitcoin.Features.BlockStore;
...
@@ -17,6 +17,7 @@ using Stratis.Bitcoin.Features.BlockStore;
using
Stratis.Bitcoin.Features.Consensus
;
using
Stratis.Bitcoin.Features.Consensus
;
using
Stratis.Bitcoin.Features.MemoryPool
;
using
Stratis.Bitcoin.Features.MemoryPool
;
using
Stratis.Bitcoin.Features.Miner
;
using
Stratis.Bitcoin.Features.Miner
;
using
Stratis.Bitcoin.Features.Miner.Interfaces
;
using
Stratis.Bitcoin.Features.RPC
;
using
Stratis.Bitcoin.Features.RPC
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.Features.Wallet.Controllers
;
using
Stratis.Bitcoin.Features.Wallet.Controllers
;
...
@@ -37,47 +38,7 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -37,47 +38,7 @@ namespace DeStream.DeStreamD.ForTest
{
{
MainAsync
(
args
).
Wait
();
MainAsync
(
args
).
Wait
();
}
}
#
region
Test
public
static
DataFolder
CreateDataFolder
(
object
caller
,
[
System
.
Runtime
.
CompilerServices
.
CallerMemberName
]
string
callingMethod
=
""
)
{
string
directoryPath
=
GetTestDirectoryPath
(
caller
,
callingMethod
);
var
dataFolder
=
new
DataFolder
(
new
NodeSettings
(
args
:
new
string
[]
{
$"-datadir=
{
AssureEmptyDir
(
directoryPath
)}
"
}).
DataDir
);
return
dataFolder
;
}
public
static
string
GetTestDirectoryPath
(
object
caller
,
[
System
.
Runtime
.
CompilerServices
.
CallerMemberName
]
string
callingMethod
=
""
)
{
return
GetTestDirectoryPath
(
Path
.
Combine
(
caller
.
GetType
().
Name
,
callingMethod
));
}
public
static
string
AssureEmptyDir
(
string
dir
)
{
int
deleteAttempts
=
0
;
while
(
deleteAttempts
<
50
)
{
if
(
Directory
.
Exists
(
dir
))
{
try
{
Directory
.
Delete
(
dir
,
true
);
break
;
}
catch
{
deleteAttempts
++;
Thread
.
Sleep
(
200
);
}
}
else
break
;
}
if
(
deleteAttempts
>=
50
)
throw
new
Exception
(
string
.
Format
(
"The test folder: {0} could not be deleted."
,
dir
));
Directory
.
CreateDirectory
(
dir
);
return
dir
;
}
#
endregion
public
static
async
Task
MainAsync
(
string
[]
args
)
public
static
async
Task
MainAsync
(
string
[]
args
)
{
{
...
@@ -101,76 +62,35 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -101,76 +62,35 @@ namespace DeStream.DeStreamD.ForTest
.
UseBlockStore
()
.
UseBlockStore
()
.
UsePosConsensus
()
.
UsePosConsensus
()
.
UseMempool
()
.
UseMempool
()
.
UseWallet
()
.
UseWallet
DeStream
()
.
AddPowPosMining
()
.
AddPowPosMining
()
.
UseApi
()
.
UseApi
()
.
AddRPC
()
.
AddRPC
()
.
Build
();
.
Build
();
var
walletManager
=
node
.
WalletManager
();
node
.
Services
.
ServiceProvider
.
GetService
<
IPowMining
>().
GenerateBlocks
(
new
ReserveScript
{
ReserveFullNodeScript
=
MinerSecret
.
ScriptPubKey
},
3
,
uint
.
MaxValue
);
Wallet
wallet
=
TestClassHelper
.
CreateFirstTransaction
(
nodeSettings
,
walletManager
);
var
walletManager
=
(
DeStreamWalletManager
)
node
.
WalletManager
();
walletManager
.
Wallets
.
Add
(
wallet
);
//var x= node.WalletManager().CreateWallet("password", "MyWallet");
//Wallet MyWallet = null;
//try
//{
// MyWallet = node.NodeService<IWalletManager>().LoadWallet("password", "MyWallet");
//}
//catch (Exception ex)
//{
// node.WalletManager().CreateWallet("password", "MyWallet");
//}
//TestClassHelper.CreateFirstTransaction(MyWallet, nodeSettings);
//node.NodeService<IWalletManager>().SaveWallet(MyWallet);
//Wallet wallet = TestClassHelper.CreateFirstTransaction(nodeSettings, ref walletManager, node.NodeService<WalletSettings>(),
// node.NodeService<IWalletFeePolicy>());
//(Wallet wallet, Block block, ChainedHeader chainedHeader) test = TestClassHelper.CreateFirstTransaction(nodeSettings, ref walletManager, node.NodeService<WalletSettings>(),
// node.NodeService<IWalletFeePolicy>());
//((WalletManager)node.NodeService<IWalletManager>()).Wallets.Add(test.wallet);
//(ExtKey ExtKey, string ExtPubKey) accountKeys = TestClassHelper.GenerateAccountKeys(MyWallet, "password", "m/44'/0'/0'");
//((WalletManager)node.NodeService<IWalletManager>()).LoadKeysLookupLock();
//(PubKey PubKey, BitcoinPubKeyAddress Address) spendingKeys = TestClassHelper.GenerateAddressKeys(MyWallet, accountKeys.ExtPubKey, "0/0");
//((WalletManager)node.NodeService<IWalletManager>()).WalletTipHash = test.block.Header.GetHash();
//(PubKey PubKey, BitcoinPubKeyAddress Address) destinationKeys = TestClassHelper.GenerateAddressKeys(MyWallet, accountKeys.ExtPubKey, "0/1");
//(PubKey PubKey, BitcoinPubKeyAddress Address) changeKeys = TestClassHelper.GenerateAddressKeys(MyWallet, accountKeys.ExtPubKey, "1/0");
//var spendingAddress = new HdAddress
//((WalletManager)node.NodeService<IWalletManager>()).ProcessBlock(test.block, test.chainedHeader);
//{
// Index = 0,
// HdPath = $"m/44'/0'/0'/0/0",
// Address = spendingKeys.Address.ToString(),
// Pubkey = spendingKeys.PubKey.ScriptPubKey,
// ScriptPubKey = spendingKeys.Address.ScriptPubKey,
// Transactions = new List<TransactionData>()
//};
//var destinationAddress = new HdAddress
//{
// Index = 1,
// HdPath = $"m/44'/0'/0'/0/1",
// Address = destinationKeys.Address.ToString(),
// Pubkey = destinationKeys.PubKey.ScriptPubKey,
// ScriptPubKey = destinationKeys.Address.ScriptPubKey,
// Transactions = new List<TransactionData>()
//};
//var changeAddress = new HdAddress
//walletManager.SaveWallets();
//{
//walletManager.Wallets.Add(wallet);
// Index = 0,
// HdPath = $"m/44'/0'/0'/1/0",
// Address = changeKeys.Address.ToString(),
// Pubkey = changeKeys.PubKey.ScriptPubKey,
// ScriptPubKey = changeKeys.Address.ScriptPubKey,
// Transactions = new List<TransactionData>()
//};
//(ConcurrentChain chain, uint256 blockhash, Block block) chainInfo = TestClassHelper.CreateChainAndCreateFirstBlockWithPaymentToAddress(MyWallet.Network, spendingAddress);
int
qwe0
=
1
;
//var transaction = chainInfo.block.Transactions[0];
//int blockHeight = chainInfo.chain.GetBlock(chainInfo.block.GetHash()).Height;
//var walletManager = node.WalletManager();
//walletManager.ProcessTransaction(transaction, blockHeight);
//ChainedHeader chainedBlock = chainInfo.chain.GetBlock(chainInfo.block.GetHash());
//walletManager.ProcessBlock(chainInfo.block, chainedBlock);
int
qwe
=
1
;
if
(
node
!=
null
)
if
(
node
!=
null
)
await
node
.
RunAsync
();
await
node
.
RunAsync
();
int
qwe
=
1
;
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
...
...
Sources/DeStream.DeStreamD.ForTest/TestClassHelper.cs
View file @
80032683
...
@@ -2,12 +2,16 @@
...
@@ -2,12 +2,16 @@
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Linq
;
using
System.Text
;
using
System.Text
;
using
System.Threading
;
using
DeStream.Stratis.Bitcoin.Configuration
;
using
DeStream.Stratis.Bitcoin.Configuration
;
using
Moq
;
using
Moq
;
using
NBitcoin
;
using
NBitcoin
;
using
Stratis.Bitcoin
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.Features.Wallet.Interfaces
;
using
Stratis.Bitcoin.Features.Wallet.Interfaces
;
using
Stratis.Bitcoin.IntegrationTests.Common.EnvironmentMockUpHelpers
;
using
Stratis.Bitcoin.Utilities
;
using
Stratis.Bitcoin.Utilities
;
using
static
Stratis
.
Bitcoin
.
BlockPulling
.
BlockPuller
;
namespace
DeStream.DeStreamD.ForTest
namespace
DeStream.DeStreamD.ForTest
{
{
...
@@ -29,11 +33,15 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -29,11 +33,15 @@ namespace DeStream.DeStreamD.ForTest
}
}
public
static
(
ConcurrentChain
chain
,
uint256
blockhash
,
Block
block
)
CreateChainAndCreateFirstBlockWithPaymentToAddress
(
Network
network
,
HdAddress
address
)
public
static
(
ConcurrentChain
chain
,
uint256
blockhash
,
Block
block
)
CreateChainAndCreateFirstBlockWithPaymentToAddress
(
DeStreamWalletManager
walletManager
,
Network
network
,
HdAddress
address
)
{
{
var
chain
=
new
ConcurrentChain
(
network
);
var
chain
=
new
ConcurrentChain
(
network
);
//var chain = walletManager.Chain;
var
block
=
new
Block
();
var
block
=
new
Block
();
//var block = network.GetGenesis().Header;
block
.
Header
.
HashPrevBlock
=
chain
.
Tip
.
HashBlock
;
block
.
Header
.
HashPrevBlock
=
chain
.
Tip
.
HashBlock
;
block
.
Header
.
Bits
=
block
.
Header
.
GetWorkRequired
(
network
,
chain
.
Tip
);
block
.
Header
.
Bits
=
block
.
Header
.
GetWorkRequired
(
network
,
chain
.
Tip
);
block
.
Header
.
UpdateTime
(
DateTimeOffset
.
UtcNow
,
network
,
chain
.
Tip
);
block
.
Header
.
UpdateTime
(
DateTimeOffset
.
UtcNow
,
network
,
chain
.
Tip
);
...
@@ -48,7 +56,7 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -48,7 +56,7 @@ namespace DeStream.DeStreamD.ForTest
block
.
Header
.
PrecomputeHash
();
block
.
Header
.
PrecomputeHash
();
chain
.
SetTip
(
block
.
Header
);
chain
.
SetTip
(
block
.
Header
);
return
(
chain
,
block
.
GetHash
(),
block
);
return
(
chain
,
block
.
GetHash
(),
block
);
}
}
...
@@ -126,7 +134,10 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -126,7 +134,10 @@ namespace DeStream.DeStreamD.ForTest
return
(
walletFile
,
extendedKey
);
return
(
walletFile
,
extendedKey
);
}
}
public
static
Wallet
CreateFirstTransaction
(
DeStreamNodeSettings
nodeSettings
,
WalletManager
walletManager
)
//public static Wallet CreateFirstTransaction(DeStreamNodeSettings nodeSettings, ref DeStreamWalletManager walletManager, WalletSettings walletSettings,
// IWalletFeePolicy _walletFeePolicy)
public
static
(
Wallet
wallet
,
Block
block
,
ChainedHeader
chainedHeader
)
CreateFirstTransaction
(
DeStreamNodeSettings
nodeSettings
,
ref
DeStreamWalletManager
walletManager
,
WalletSettings
walletSettings
,
IWalletFeePolicy
_walletFeePolicy
)
{
{
Wallet
wallet
=
GenerateBlankWalletWithExtKey
(
"myWallet1"
,
"password"
).
wallet
;
Wallet
wallet
=
GenerateBlankWalletWithExtKey
(
"myWallet1"
,
"password"
).
wallet
;
(
ExtKey
ExtKey
,
string
ExtPubKey
)
accountKeys
=
GenerateAccountKeys
(
wallet
,
"password"
,
"m/44'/0'/0'"
);
(
ExtKey
ExtKey
,
string
ExtPubKey
)
accountKeys
=
GenerateAccountKeys
(
wallet
,
"password"
,
"m/44'/0'/0'"
);
...
@@ -165,7 +176,7 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -165,7 +176,7 @@ namespace DeStream.DeStreamD.ForTest
};
};
//Generate a spendable transaction
//Generate a spendable transaction
(
ConcurrentChain
chain
,
uint256
blockhash
,
Block
block
)
chainInfo
=
CreateChainAndCreateFirstBlockWithPaymentToAddress
(
wallet
.
Network
,
spendingAddress
);
(
ConcurrentChain
chain
,
uint256
blockhash
,
Block
block
)
chainInfo
=
CreateChainAndCreateFirstBlockWithPaymentToAddress
(
wallet
Manager
,
wallet
.
Network
,
spendingAddress
);
TransactionData
spendingTransaction
=
CreateTransactionDataFromFirstBlock
(
chainInfo
);
TransactionData
spendingTransaction
=
CreateTransactionDataFromFirstBlock
(
chainInfo
);
spendingAddress
.
Transactions
.
Add
(
spendingTransaction
);
spendingAddress
.
Transactions
.
Add
(
spendingTransaction
);
...
@@ -176,13 +187,14 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -176,13 +187,14 @@ namespace DeStream.DeStreamD.ForTest
wallet
.
AccountsRoot
.
ElementAt
(
0
).
Accounts
.
Add
(
new
HdAccount
wallet
.
AccountsRoot
.
ElementAt
(
0
).
Accounts
.
Add
(
new
HdAccount
{
{
Index
=
0
,
Index
=
1
,
Name
=
"account1"
,
Name
=
"account1"
,
HdPath
=
"m/44'/0'/0'"
,
HdPath
=
"m/44'/0'/0'"
,
ExtendedPubKey
=
accountKeys
.
ExtPubKey
,
ExtendedPubKey
=
accountKeys
.
ExtPubKey
,
//ExternalAddresses = new List<HdAddress> { spendingAddress, destinationAddress },
//ExternalAddresses = new List<HdAddress> { spendingAddress, destinationAddress },
ExternalAddresses
=
new
List
<
HdAddress
>
{
spendingAddress
},
ExternalAddresses
=
new
List
<
HdAddress
>
{
spendingAddress
},
InternalAddresses
=
new
List
<
HdAddress
>
{
changeAddress
}
//InternalAddresses = new List<HdAddress> { changeAddress }
InternalAddresses
=
new
List
<
HdAddress
>
{
destinationAddress
}
});
});
var
walletFeePolicy
=
new
Mock
<
IWalletFeePolicy
>();
var
walletFeePolicy
=
new
Mock
<
IWalletFeePolicy
>();
...
@@ -190,19 +202,24 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -190,19 +202,24 @@ namespace DeStream.DeStreamD.ForTest
.
Returns
(
new
Money
(
5000
));
.
Returns
(
new
Money
(
5000
));
HdAddress
spentAddressResult0
=
wallet
.
AccountsRoot
.
ElementAt
(
0
).
Accounts
.
ElementAt
(
0
).
ExternalAddresses
.
ElementAt
(
0
);
HdAddress
spentAddressResult0
=
wallet
.
AccountsRoot
.
ElementAt
(
0
).
Accounts
.
ElementAt
(
0
).
ExternalAddresses
.
ElementAt
(
0
);
//var walletManager = new WalletManager(nodeSettings.LoggerFactory, Network.Main, chainInfo.chain, nodeSettings, new Mock<WalletSettings>().Object,
//var
_
walletManager = new WalletManager(nodeSettings.LoggerFactory, Network.Main, chainInfo.chain, nodeSettings, new Mock<WalletSettings>().Object,
// nodeSettings.DataFolder, walletFeePolicy.Object, new Mock<IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default);
// nodeSettings.DataFolder, walletFeePolicy.Object, new Mock<IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default);
walletManager
=
new
DeStreamWalletManager
(
nodeSettings
.
LoggerFactory
,
nodeSettings
.
Network
,
chainInfo
.
chain
,
nodeSettings
,
walletSettings
,
nodeSettings
.
DataFolder
,
walletFeePolicy
.
Object
,
walletManager
.
AsyncLoopFactory
,
walletManager
.
NodeLifetime
,
walletManager
.
DateTimeProvider
);
walletManager
.
Wallets
.
Add
(
wallet
);
walletManager
.
Wallets
.
Add
(
wallet
);
walletManager
.
LoadKeysLookupLock
();
walletManager
.
LoadKeysLookupLock
();
walletManager
.
WalletTipHash
=
block
.
Header
.
GetHash
();
walletManager
.
WalletTipHash
=
block
.
Header
.
GetHash
();
ChainedHeader
chainedBlock
=
chainInfo
.
chain
.
GetBlock
(
block
.
GetHash
());
ChainedHeader
chainedBlock
=
chainInfo
.
chain
.
GetBlock
(
block
.
GetHash
());
walletManager
.
ProcessTransaction
(
transaction
,
null
,
block
,
false
);
//
walletManager.ProcessTransaction(transaction, null, block, false);
//
walletManager.ProcessBlock(block, chainedBlock);
walletManager
.
ProcessBlock
(
block
,
chainedBlock
);
return
(
wallet
,
block
,
chainedBlock
);
HdAddress
spentAddressResult
=
wallet
.
AccountsRoot
.
ElementAt
(
0
).
Accounts
.
ElementAt
(
0
).
ExternalAddresses
.
ElementAt
(
0
);
//
HdAddress spentAddressResult = wallet.AccountsRoot.ElementAt(0).Accounts.ElementAt(0).ExternalAddresses.ElementAt(0);
return
wallet
;
//
return wallet;
}
}
public
static
Money
Get9Billion
()
public
static
Money
Get9Billion
()
...
@@ -210,5 +227,91 @@ namespace DeStream.DeStreamD.ForTest
...
@@ -210,5 +227,91 @@ namespace DeStream.DeStreamD.ForTest
return
new
Money
(
9000000000
);
return
new
Money
(
9000000000
);
}
}
public
static
void
CreateTestBlock
(
FullNode
fullNode
,
BitcoinSecret
minerSecret
)
{
//FullNode fullNode = (this.runner as StratisBitcoinPowRunner).FullNode;
BitcoinSecret
dest
=
minerSecret
;
var
blocks
=
new
List
<
Block
>();
List
<
Transaction
>
passedTransactions
=
null
;
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
uint
nonce
=
0
;
var
block
=
new
Block
();
block
.
Header
.
HashPrevBlock
=
fullNode
.
Chain
.
Tip
.
HashBlock
;
block
.
Header
.
Bits
=
block
.
Header
.
GetWorkRequired
(
fullNode
.
Network
,
fullNode
.
Chain
.
Tip
);
block
.
Header
.
UpdateTime
(
DateTimeOffset
.
UtcNow
,
fullNode
.
Network
,
fullNode
.
Chain
.
Tip
);
var
coinbase
=
new
Transaction
();
coinbase
.
AddInput
(
TxIn
.
CreateCoinbase
(
fullNode
.
Chain
.
Height
+
1
));
coinbase
.
AddOutput
(
new
TxOut
(
fullNode
.
Network
.
GetReward
(
fullNode
.
Chain
.
Height
+
1
),
dest
.
GetAddress
()));
block
.
AddTransaction
(
coinbase
);
if
(
passedTransactions
?.
Any
()
??
false
)
{
passedTransactions
=
Reorder
(
passedTransactions
);
block
.
Transactions
.
AddRange
(
passedTransactions
);
}
block
.
UpdateMerkleRoot
();
while
(!
block
.
CheckProofOfWork
())
block
.
Header
.
Nonce
=
++
nonce
;
blocks
.
Add
(
block
);
uint256
blockHash
=
block
.
GetHash
();
var
newChain
=
new
ChainedHeader
(
block
.
Header
,
blockHash
,
fullNode
.
Chain
.
Tip
);
ChainedHeader
oldTip
=
fullNode
.
Chain
.
SetTip
(
newChain
);
fullNode
.
ConsensusLoop
().
Puller
.
InjectBlock
(
blockHash
,
new
DownloadedBlock
{
Length
=
block
.
GetSerializedSize
(),
Block
=
block
},
CancellationToken
.
None
);
}
}
private
class
TransactionNode
{
public
uint256
Hash
=
null
;
public
Transaction
Transaction
=
null
;
public
List
<
TransactionNode
>
DependsOn
=
new
List
<
TransactionNode
>();
public
TransactionNode
(
Transaction
tx
)
{
this
.
Transaction
=
tx
;
this
.
Hash
=
tx
.
GetHash
();
}
}
private
static
List
<
Transaction
>
Reorder
(
List
<
Transaction
>
transactions
)
{
if
(
transactions
.
Count
==
0
)
return
transactions
;
var
result
=
new
List
<
Transaction
>();
Dictionary
<
uint256
,
TransactionNode
>
dictionary
=
transactions
.
ToDictionary
(
t
=>
t
.
GetHash
(),
t
=>
new
TransactionNode
(
t
));
foreach
(
TransactionNode
transaction
in
dictionary
.
Select
(
d
=>
d
.
Value
))
{
foreach
(
TxIn
input
in
transaction
.
Transaction
.
Inputs
)
{
TransactionNode
node
=
dictionary
.
TryGet
(
input
.
PrevOut
.
Hash
);
if
(
node
!=
null
)
{
transaction
.
DependsOn
.
Add
(
node
);
}
}
}
while
(
dictionary
.
Count
!=
0
)
{
foreach
(
TransactionNode
node
in
dictionary
.
Select
(
d
=>
d
.
Value
).
ToList
())
{
foreach
(
TransactionNode
parent
in
node
.
DependsOn
.
ToList
())
{
if
(!
dictionary
.
ContainsKey
(
parent
.
Hash
))
node
.
DependsOn
.
Remove
(
parent
);
}
if
(
node
.
DependsOn
.
Count
==
0
)
{
result
.
Add
(
node
.
Transaction
);
dictionary
.
Remove
(
node
.
Hash
);
}
}
}
return
result
;
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment