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
1be933f6
Commit
1be933f6
authored
Aug 08, 2018
by
Pavel Pavlov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bugfix
parent
3c8c9867
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
67 additions
and
1719 deletions
+67
-1719
Program.cs
Sources/DeStream.DeStreamD.ForTest/Program.cs
+17
-8
TestClassHelper.cs
Sources/DeStream.DeStreamD.ForTest/TestClassHelper.cs
+41
-40
DeStreamTest.cs
Sources/NBitcoin/Networks/DeStreamTest.cs
+4
-1
NodeConnectionBuilder.cs
...itcoin.IntegrationTests/Builders/NodeConnectionBuilder.cs
+0
-61
NodeGroupBuilder.cs
...tis.Bitcoin.IntegrationTests/Builders/NodeGroupBuilder.cs
+0
-76
CoreNode.cs
...oin.IntegrationTests/EnvironmentMockUpHelpers/CoreNode.cs
+0
-654
InitialBlockDownloadStateMock.cs
...EnvironmentMockUpHelpers/InitialBlockDownloadStateMock.cs
+0
-52
NetworkSimulator.cs
...grationTests/EnvironmentMockUpHelpers/NetworkSimulator.cs
+0
-70
NodeBuilder.cs
....IntegrationTests/EnvironmentMockUpHelpers/NodeBuilder.cs
+0
-283
NodeRunners.cs
....IntegrationTests/EnvironmentMockUpHelpers/NodeRunners.cs
+0
-221
CoreNodeExtensions.cs
...Bitcoin.IntegrationTests/Extensions/CoreNodeExtensions.cs
+0
-43
FullNodeTestBuilderExtension.cs
...tegrationTests/Extensions/FullNodeTestBuilderExtension.cs
+0
-61
SharedSteps.cs
Sources/Stratis.Bitcoin.IntegrationTests/SharedSteps.cs
+0
-85
Stratis.Bitcoin.IntegrationTests.csproj
....IntegrationTests/Stratis.Bitcoin.IntegrationTests.csproj
+5
-0
TestHelper.cs
Sources/Stratis.Bitcoin.IntegrationTests/TestHelper.cs
+0
-64
No files found.
Sources/DeStream.DeStreamD.ForTest/Program.cs
View file @
1be933f6
...
...
@@ -38,7 +38,7 @@ namespace DeStream.DeStreamD.ForTest
{
MainAsync
(
args
).
Wait
();
}
public
static
async
Task
MainAsync
(
string
[]
args
)
{
...
...
@@ -54,7 +54,7 @@ namespace DeStream.DeStreamD.ForTest
Console
.
WriteLine
(
$"current network:
{
network
.
Name
}
"
);
// NOTES: running BTC and STRAT side by side is not possible yet as the flags for serialization are static
FullNode
node
=
(
FullNode
)
new
FullNodeBuilder
()
...
...
@@ -62,25 +62,34 @@ namespace DeStream.DeStreamD.ForTest
.
UseBlockStore
()
.
UsePosConsensus
()
.
UseMempool
()
.
UseWallet
DeStream
()
.
UseWallet
()
.
AddPowPosMining
()
.
UseApi
()
.
AddRPC
()
.
Build
();
node
.
Services
.
ServiceProvider
.
GetService
<
IPowMining
>().
GenerateBlocks
(
new
ReserveScript
{
ReserveFullNodeScript
=
MinerSecret
.
ScriptPubKey
},
3
,
uint
.
MaxValue
);
var
walletManager
=
(
DeStreamWalletManager
)
node
.
WalletManager
();
(
Wallet
wallet
,
Block
block
,
ChainedHeader
chainedHeader
)
result
=
TestClassHelper
.
CreateFirstTransaction
(
nodeSettings
,
node
.
WalletManager
(),
node
.
NodeService
<
WalletSettings
>(),
node
.
NodeService
<
IWalletFeePolicy
>());
var
walletManager
=
node
.
WalletManager
();
walletManager
.
Wallets
.
Add
(
result
.
wallet
);
//HdAddress addr = node.WalletManager().GetUnusedAddress(new WalletAccountReference("myWallet1", "account1"));
//HdAddress addr = result.wallet.AccountsRoot.ElementAt(0).Accounts.ElementAt(0).ExternalAddresses.ElementAt(0).Address;
//HdAddress addr = new HdAddress();
HdAddress
addr
=
result
.
wallet
.
AccountsRoot
.
ElementAt
(
0
).
Accounts
.
ElementAt
(
0
).
ExternalAddresses
.
ElementAt
(
0
);
Key
key
=
result
.
wallet
.
GetExtendedPrivateKeyForAddress
(
"password"
,
addr
).
PrivateKey
;
TestClassHelper
.
CreateTestBlock
(
node
,
key
);
//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);
//((WalletManager)node.NodeService<IWalletManager>()).LoadKeysLookupLock();
//((WalletManager)node.NodeService<IWalletManager>()).WalletTipHash = test.block.Header.GetHash();
//((WalletManager)node.NodeService<IWalletManager>()).WalletTipHash = test.block.Header.GetHash();
//((WalletManager)node.NodeService<IWalletManager>()).ProcessBlock(test.block, test.chainedHeader);
...
...
Sources/DeStream.DeStreamD.ForTest/TestClassHelper.cs
View file @
1be933f6
...
...
@@ -33,15 +33,15 @@ namespace DeStream.DeStreamD.ForTest
}
public
static
(
ConcurrentChain
chain
,
uint256
blockhash
,
Block
block
)
CreateChainAndCreateFirstBlockWithPaymentToAddress
(
DeStream
WalletManager
walletManager
,
Network
network
,
HdAddress
address
)
public
static
(
ConcurrentChain
chain
,
uint256
blockhash
,
Block
block
)
CreateChainAndCreateFirstBlockWithPaymentToAddress
(
WalletManager
walletManager
,
Network
network
,
HdAddress
address
)
{
var
chain
=
new
ConcurrentChain
(
network
);
//var chain = walletManager.Chain;
var
block
=
new
Block
();
//var block = network.GetGenesis().Header;
block
.
Header
.
HashPrevBlock
=
chain
.
Tip
.
HashBlock
;
block
.
Header
.
Bits
=
block
.
Header
.
GetWorkRequired
(
network
,
chain
.
Tip
);
block
.
Header
.
UpdateTime
(
DateTimeOffset
.
UtcNow
,
network
,
chain
.
Tip
);
...
...
@@ -56,7 +56,7 @@ namespace DeStream.DeStreamD.ForTest
block
.
Header
.
PrecomputeHash
();
chain
.
SetTip
(
block
.
Header
);
return
(
chain
,
block
.
GetHash
(),
block
);
}
...
...
@@ -136,7 +136,7 @@ namespace DeStream.DeStreamD.ForTest
//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
DeStream
WalletManager
walletManager
,
WalletSettings
walletSettings
,
public
static
(
Wallet
wallet
,
Block
block
,
ChainedHeader
chainedHeader
)
CreateFirstTransaction
(
DeStreamNodeSettings
nodeSettings
,
WalletManager
walletManager
,
WalletSettings
walletSettings
,
IWalletFeePolicy
_walletFeePolicy
)
{
Wallet
wallet
=
GenerateBlankWalletWithExtKey
(
"myWallet1"
,
"password"
).
wallet
;
...
...
@@ -204,18 +204,18 @@ namespace DeStream.DeStreamD.ForTest
//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);
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
.
LoadKeysLookupLock
();
walletManager
.
WalletTipHash
=
block
.
Header
.
GetHash
();
//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.LoadKeysLookupLock();
//walletManager.WalletTipHash = block.Header.GetHash();
ChainedHeader
chainedBlock
=
chainInfo
.
chain
.
GetBlock
(
block
.
GetHash
());
//walletManager.ProcessTransaction(transaction, null, block, false);
walletManager
.
ProcessBlock
(
block
,
chainedBlock
);
//
//
walletManager.ProcessTransaction(transaction, null, block, false);
//
walletManager.ProcessBlock(block, chainedBlock);
return
(
wallet
,
block
,
chainedBlock
);
//HdAddress spentAddressResult = wallet.AccountsRoot.ElementAt(0).Accounts.ElementAt(0).ExternalAddresses.ElementAt(0);
...
...
@@ -227,40 +227,40 @@ namespace DeStream.DeStreamD.ForTest
return
new
Money
(
9000000000
);
}
public
static
void
CreateTestBlock
(
FullNode
fullNode
,
BitcoinSecret
minerSecret
)
public
static
Block
CreateTestBlock
(
FullNode
fullNode
,
Key
key
)
{
//FullNode fullNode = (this.runner as StratisBitcoinPowRunner).FullNode;
BitcoinSecret
dest
=
minerSecret
;
BitcoinSecret
dest
=
new
BitcoinSecret
(
key
,
fullNode
.
Network
);
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
(
Get9Billion
(),
dest
.
GetAddress
()));
block
.
AddTransaction
(
coinbase
);
if
(
passedTransactions
?.
Any
()
??
false
)
{
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
);
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
);
return
block
;
}
private
class
TransactionNode
{
public
uint256
Hash
=
null
;
...
...
@@ -315,3 +315,4 @@ namespace DeStream.DeStreamD.ForTest
}
}
}
\ No newline at end of file
Sources/NBitcoin/Networks/DeStreamTest.cs
View file @
1be933f6
...
...
@@ -72,9 +72,12 @@ namespace NBitcoin.Networks
genesis
.
Header
.
Bits
=
this
.
Consensus
.
PowLimit
;
this
.
Genesis
=
genesis
;
this
.
Consensus
.
HashGenesisBlock
=
genesis
.
GetHash
();
//f79e424c3636eb124bb6d07dcc2266e57575c68b738eb3adae364cd3a6ef2943
Assert
(
this
.
Consensus
.
HashGenesisBlock
==
uint256
.
Parse
(
"0x00000e246d7b73b88c9ab55f2e5e94d9e22d471def3df5ea448f5576b1d156b9"
));
//Assert(this.Consensus.HashGenesisBlock == uint256.Parse("
5c69790173d48daf2a2a111e0baafb0546ebbec9a831f890ff8c7e23fe119885
"));
//Assert(this.Consensus.HashGenesisBlock == uint256.Parse("
f79e424c3636eb124bb6d07dcc2266e57575c68b738eb3adae364cd3a6ef2943
"));
this
.
Checkpoints
=
new
Dictionary
<
int
,
CheckpointInfo
>
{
...
...
Sources/Stratis.Bitcoin.IntegrationTests/Builders/NodeConnectionBuilder.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
;
namespace
Stratis.Bitcoin.IntegrationTests.Builders
{
public
class
NodeConnectionBuilder
{
private
readonly
NodeGroupBuilder
parentNodeGroupBuilder
;
private
IDictionary
<
string
,
CoreNode
>
nodes
;
private
SharedSteps
sharedSteps
;
private
NodeConnectionBuilder
()
{
this
.
sharedSteps
=
new
SharedSteps
();
}
public
NodeConnectionBuilder
(
NodeGroupBuilder
parentNodeGroupBuilder
)
:
this
()
{
this
.
parentNodeGroupBuilder
=
parentNodeGroupBuilder
;
}
public
NodeConnectionBuilder
(
IDictionary
<
string
,
CoreNode
>
nodesDictionary
)
:
this
()
{
this
.
nodes
=
nodesDictionary
;
}
public
NodeConnectionBuilder
With
(
IDictionary
<
string
,
CoreNode
>
nodes
)
{
this
.
nodes
=
nodes
;
return
this
;
}
public
NodeConnectionBuilder
Connect
(
string
from
,
string
to
)
{
this
.
nodes
[
from
].
CreateRPCClient
().
AddNode
(
this
.
nodes
[
to
].
Endpoint
,
true
);
this
.
sharedSteps
.
WaitForNodeToSync
(
this
.
nodes
[
from
],
this
.
nodes
[
to
]);
return
this
;
}
public
NodeGroupBuilder
AndNoMoreConnections
()
{
if
(
this
.
parentNodeGroupBuilder
==
null
)
throw
new
NotSupportedException
(
"Pass parent builder into constructor if you need to return to that builder to continue building."
);
return
this
.
parentNodeGroupBuilder
;
}
public
void
DisconnectAll
()
{
foreach
(
var
node
in
this
.
nodes
)
{
foreach
(
var
otherNode
in
this
.
nodes
.
Where
(
x
=>
x
.
Key
!=
node
.
Key
))
{
node
.
Value
.
CreateRPCClient
().
RemoveNode
(
otherNode
.
Value
.
Endpoint
);
}
}
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/Builders/NodeGroupBuilder.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
;
namespace
Stratis.Bitcoin.IntegrationTests.Builders
{
public
class
NodeGroupBuilder
:
IDisposable
{
private
readonly
NodeBuilder
nodeBuilder
;
private
readonly
Dictionary
<
string
,
CoreNode
>
nodes
;
public
NodeGroupBuilder
(
string
testFolder
)
{
this
.
nodeBuilder
=
NodeBuilder
.
Create
(
caller
:
testFolder
);
this
.
nodes
=
new
Dictionary
<
string
,
CoreNode
>();
}
public
void
Dispose
()
{
this
.
nodeBuilder
.
Dispose
();
}
public
IDictionary
<
string
,
CoreNode
>
Build
()
{
return
this
.
nodes
;
}
public
NodeGroupBuilder
StratisPowNode
(
string
nodeName
)
{
this
.
nodes
.
Add
(
nodeName
,
this
.
nodeBuilder
.
CreateStratisPowNode
());
return
this
;
}
public
NodeGroupBuilder
CreateStratisPowMiningNode
(
string
nodeName
)
{
this
.
nodes
.
Add
(
nodeName
,
this
.
nodeBuilder
.
CreateStratisPowMiningNode
());
return
this
;
}
public
NodeGroupBuilder
CreateStratisPosNode
(
string
nodeName
)
{
this
.
nodes
.
Add
(
nodeName
,
this
.
nodeBuilder
.
CreateStratisPosNode
());
return
this
;
}
public
NodeGroupBuilder
CreateStratisPosApiNode
(
string
nodeName
)
{
this
.
nodes
.
Add
(
nodeName
,
this
.
nodeBuilder
.
CreateStratisPosApiNode
());
return
this
;
}
public
NodeGroupBuilder
NotInIBD
()
{
this
.
nodes
.
Last
().
Value
.
NotInIBD
();
return
this
;
}
public
NodeGroupBuilder
WithWallet
(
string
walletName
,
string
walletPassword
)
{
this
.
nodes
.
Last
().
Value
.
FullNode
.
WalletManager
().
CreateWallet
(
walletPassword
,
walletName
);
return
this
;
}
public
NodeGroupBuilder
Start
()
{
this
.
nodes
.
Last
().
Value
.
Start
();
return
this
;
}
public
NodeConnectionBuilder
WithConnections
()
{
return
new
NodeConnectionBuilder
(
this
).
With
(
this
.
nodes
);
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/EnvironmentMockUpHelpers/CoreNode.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Linq
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.Extensions.DependencyInjection
;
using
NBitcoin
;
using
NBitcoin.DataEncoders
;
using
NBitcoin.Protocol
;
using
NBitcoin.RPC
;
using
Stratis.Bitcoin.Configuration.Logging
;
using
Stratis.Bitcoin.Features.MemoryPool
;
using
Stratis.Bitcoin.Features.Miner
;
using
Stratis.Bitcoin.Features.Miner.Interfaces
;
using
Stratis.Bitcoin.Interfaces
;
using
Stratis.Bitcoin.P2P
;
using
Stratis.Bitcoin.P2P.Peer
;
using
Stratis.Bitcoin.P2P.Protocol.Payloads
;
using
Stratis.Bitcoin.Utilities
;
using
static
Stratis
.
Bitcoin
.
BlockPulling
.
BlockPuller
;
namespace
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
{
public
class
CoreNode
{
/// <summary>Factory for creating P2P network peers.</summary>
private
readonly
INetworkPeerFactory
networkPeerFactory
;
private
int
[]
ports
;
private
NodeRunner
runner
;
private
readonly
NetworkCredential
creds
;
private
List
<
Transaction
>
transactions
=
new
List
<
Transaction
>();
private
HashSet
<
OutPoint
>
locked
=
new
HashSet
<
OutPoint
>();
private
Money
fee
=
Money
.
Coins
(
0.0001
m
);
private
object
lockObject
=
new
object
();
/// <summary>Location of the data directory for the node.</summary>
public
string
DataFolder
{
get
{
return
this
.
runner
.
DataFolder
;
}
}
public
IPEndPoint
Endpoint
{
get
{
return
new
IPEndPoint
(
IPAddress
.
Parse
(
"127.0.0.1"
),
this
.
ports
[
0
]);
}
}
public
string
Config
{
get
;
}
public
NodeConfigParameters
ConfigParameters
{
get
;
}
=
new
NodeConfigParameters
();
public
CoreNode
(
NodeRunner
runner
,
NodeBuilder
builder
,
Network
network
,
string
configfile
)
{
this
.
runner
=
runner
;
this
.
State
=
CoreNodeState
.
Stopped
;
var
pass
=
Encoders
.
Hex
.
EncodeData
(
RandomUtils
.
GetBytes
(
20
));
this
.
creds
=
new
NetworkCredential
(
pass
,
pass
);
this
.
Config
=
Path
.
Combine
(
this
.
runner
.
DataFolder
,
configfile
);
this
.
ConfigParameters
.
Import
(
builder
.
ConfigParameters
);
this
.
ports
=
new
int
[
2
];
this
.
FindPorts
(
this
.
ports
);
var
loggerFactory
=
new
ExtendedLoggerFactory
();
loggerFactory
.
AddConsoleWithFilters
();
this
.
networkPeerFactory
=
new
NetworkPeerFactory
(
network
,
DateTimeProvider
.
Default
,
loggerFactory
,
new
PayloadProvider
().
DiscoverPayloads
(),
new
SelfEndpointTracker
());
}
/// <summary>Get stratis full node if possible.</summary>
public
FullNode
FullNode
{
get
{
return
this
.
runner
.
FullNode
;
}
}
public
void
Sync
(
CoreNode
node
,
bool
keepConnection
=
false
)
{
var
rpc
=
this
.
CreateRPCClient
();
var
rpc1
=
node
.
CreateRPCClient
();
rpc
.
AddNode
(
node
.
Endpoint
,
true
);
while
(
rpc
.
GetBestBlockHash
()
!=
rpc1
.
GetBestBlockHash
())
{
Thread
.
Sleep
(
200
);
}
if
(!
keepConnection
)
rpc
.
RemoveNode
(
node
.
Endpoint
);
}
public
CoreNodeState
State
{
get
;
private
set
;
}
public
int
ProtocolPort
{
get
{
return
this
.
ports
[
0
];
}
}
public
void
NotInIBD
()
{
(
this
.
FullNode
.
NodeService
<
IInitialBlockDownloadState
>()
as
InitialBlockDownloadStateMock
).
SetIsInitialBlockDownload
(
false
,
DateTime
.
UtcNow
.
AddMinutes
(
5
));
}
public
RPCClient
CreateRPCClient
()
{
return
new
RPCClient
(
this
.
creds
,
new
Uri
(
"http://127.0.0.1:"
+
this
.
ports
[
1
].
ToString
()
+
"/"
),
Network
.
RegTest
);
}
public
RestClient
CreateRESTClient
()
{
return
new
RestClient
(
new
Uri
(
"http://127.0.0.1:"
+
this
.
ports
[
1
].
ToString
()
+
"/"
));
}
public
INetworkPeer
CreateNetworkPeerClient
()
{
return
this
.
networkPeerFactory
.
CreateConnectedNetworkPeerAsync
(
"127.0.0.1:"
+
this
.
ports
[
0
].
ToString
()).
GetAwaiter
().
GetResult
();
}
public
void
Start
()
{
NodeBuilder
.
CreateDataFolder
(
this
.
runner
.
DataFolder
);
var
config
=
new
NodeConfigParameters
();
config
.
Add
(
"regtest"
,
"1"
);
config
.
Add
(
"rest"
,
"1"
);
config
.
Add
(
"server"
,
"1"
);
config
.
Add
(
"txindex"
,
"1"
);
config
.
Add
(
"rpcuser"
,
this
.
creds
.
UserName
);
config
.
Add
(
"rpcpassword"
,
this
.
creds
.
Password
);
config
.
Add
(
"port"
,
this
.
ports
[
0
].
ToString
());
config
.
Add
(
"rpcport"
,
this
.
ports
[
1
].
ToString
());
config
.
Add
(
"printtoconsole"
,
"1"
);
config
.
Add
(
"keypool"
,
"10"
);
config
.
Add
(
"agentprefix"
,
"node"
+
this
.
ports
[
0
].
ToString
());
config
.
Import
(
this
.
ConfigParameters
);
File
.
WriteAllText
(
this
.
Config
,
config
.
ToString
());
lock
(
this
.
lockObject
)
{
this
.
runner
.
Start
();
this
.
State
=
CoreNodeState
.
Starting
;
}
if
(
this
.
runner
is
BitcoinCoreRunner
)
StartBitcoinCoreRunner
();
else
StartStratisRunner
();
this
.
State
=
CoreNodeState
.
Running
;
}
private
void
StartBitcoinCoreRunner
()
{
while
(
true
)
{
try
{
CreateRPCClient
().
GetBlockHashAsync
(
0
).
GetAwaiter
().
GetResult
();
this
.
State
=
CoreNodeState
.
Running
;
break
;
}
catch
{
}
Task
.
Delay
(
200
);
}
}
private
void
StartStratisRunner
()
{
while
(
true
)
{
if
(
this
.
runner
.
FullNode
==
null
)
{
Thread
.
Sleep
(
100
);
continue
;
}
if
(
this
.
runner
.
FullNode
.
State
==
FullNodeState
.
Started
)
break
;
else
Thread
.
Sleep
(
200
);
}
}
private
void
FindPorts
(
int
[]
ports
)
{
int
i
=
0
;
while
(
i
<
ports
.
Length
)
{
var
port
=
RandomUtils
.
GetUInt32
()
%
4000
;
port
=
port
+
10000
;
if
(
ports
.
Any
(
p
=>
p
==
port
))
continue
;
try
{
TcpListener
l
=
new
TcpListener
(
IPAddress
.
Loopback
,
(
int
)
port
);
l
.
Start
();
l
.
Stop
();
ports
[
i
]
=
(
int
)
port
;
i
++;
}
catch
(
SocketException
)
{
}
}
}
public
void
Broadcast
(
Transaction
transaction
)
{
using
(
INetworkPeer
peer
=
this
.
CreateNetworkPeerClient
())
{
peer
.
VersionHandshakeAsync
().
GetAwaiter
().
GetResult
();
peer
.
SendMessageAsync
(
new
InvPayload
(
transaction
)).
GetAwaiter
().
GetResult
();
peer
.
SendMessageAsync
(
new
TxPayload
(
transaction
)).
GetAwaiter
().
GetResult
();
this
.
PingPongAsync
(
peer
).
GetAwaiter
().
GetResult
();
}
}
/// <summary>
/// Emit a ping and wait the pong.
/// </summary>
/// <param name="cancellation"></param>
/// <param name="peer"></param>
/// <returns>Latency.</returns>
public
async
Task
<
TimeSpan
>
PingPongAsync
(
INetworkPeer
peer
,
CancellationToken
cancellation
=
default
(
CancellationToken
))
{
using
(
var
listener
=
new
NetworkPeerListener
(
peer
))
{
var
ping
=
new
PingPayload
()
{
Nonce
=
RandomUtils
.
GetUInt64
()
};
DateTimeOffset
before
=
DateTimeOffset
.
UtcNow
;
await
peer
.
SendMessageAsync
(
ping
);
while
((
await
listener
.
ReceivePayloadAsync
<
PongPayload
>(
cancellation
).
ConfigureAwait
(
false
)).
Nonce
!=
ping
.
Nonce
)
{
}
DateTimeOffset
after
=
DateTimeOffset
.
UtcNow
;
return
after
-
before
;
}
}
public
void
SelectMempoolTransactions
()
{
var
rpc
=
this
.
CreateRPCClient
();
var
txs
=
rpc
.
GetRawMempool
();
var
tasks
=
txs
.
Select
(
t
=>
rpc
.
GetRawTransactionAsync
(
t
)).
ToArray
();
Task
.
WaitAll
(
tasks
);
this
.
transactions
.
AddRange
(
tasks
.
Select
(
t
=>
t
.
Result
).
ToArray
());
}
public
void
Split
(
Money
amount
,
int
parts
)
{
var
rpc
=
this
.
CreateRPCClient
();
TransactionBuilder
builder
=
new
TransactionBuilder
(
this
.
FullNode
.
Network
);
builder
.
AddKeys
(
rpc
.
ListSecrets
().
OfType
<
ISecret
>().
ToArray
());
builder
.
AddCoins
(
rpc
.
ListUnspent
().
Select
(
c
=>
c
.
AsCoin
()));
var
secret
=
this
.
GetFirstSecret
(
rpc
);
foreach
(
var
part
in
(
amount
-
this
.
fee
).
Split
(
parts
))
{
builder
.
Send
(
secret
,
part
);
}
builder
.
SendFees
(
this
.
fee
);
builder
.
SetChange
(
secret
);
var
tx
=
builder
.
BuildTransaction
(
true
);
this
.
Broadcast
(
tx
);
}
public
void
Kill
()
{
lock
(
this
.
lockObject
)
{
this
.
runner
.
Kill
();
this
.
State
=
CoreNodeState
.
Killed
;
}
}
public
DateTimeOffset
?
MockTime
{
get
;
set
;
}
public
void
SetMinerSecret
(
BitcoinSecret
secret
)
{
this
.
CreateRPCClient
().
ImportPrivKey
(
secret
);
this
.
MinerSecret
=
secret
;
}
public
void
SetDummyMinerSecret
(
BitcoinSecret
secret
)
{
this
.
MinerSecret
=
secret
;
}
public
BitcoinSecret
MinerSecret
{
get
;
private
set
;
}
public
async
Task
<
Block
[
]>
GenerateAsync
(
int
blockCount
,
bool
includeUnbroadcasted
=
true
,
bool
broadcast
=
true
)
{
var
rpc
=
this
.
CreateRPCClient
();
BitcoinSecret
dest
=
this
.
GetFirstSecret
(
rpc
);
var
bestBlock
=
rpc
.
GetBestBlockHash
();
ConcurrentChain
chain
=
null
;
List
<
Block
>
blocks
=
new
List
<
Block
>();
DateTimeOffset
now
=
this
.
MockTime
==
null
?
DateTimeOffset
.
UtcNow
:
this
.
MockTime
.
Value
;
using
(
INetworkPeer
peer
=
this
.
CreateNetworkPeerClient
())
{
peer
.
VersionHandshakeAsync
().
GetAwaiter
().
GetResult
();
chain
=
bestBlock
==
peer
.
Network
.
GenesisHash
?
new
ConcurrentChain
(
peer
.
Network
)
:
this
.
GetChain
(
peer
);
for
(
int
i
=
0
;
i
<
blockCount
;
i
++)
{
uint
nonce
=
0
;
Block
block
=
new
Block
();
block
.
Header
.
HashPrevBlock
=
chain
.
Tip
.
HashBlock
;
block
.
Header
.
Bits
=
block
.
Header
.
GetWorkRequired
(
rpc
.
Network
,
chain
.
Tip
);
block
.
Header
.
UpdateTime
(
now
,
rpc
.
Network
,
chain
.
Tip
);
var
coinbase
=
new
Transaction
();
coinbase
.
AddInput
(
TxIn
.
CreateCoinbase
(
chain
.
Height
+
1
));
coinbase
.
AddOutput
(
new
TxOut
(
rpc
.
Network
.
GetReward
(
chain
.
Height
+
1
),
dest
.
GetAddress
()));
block
.
AddTransaction
(
coinbase
);
if
(
includeUnbroadcasted
)
{
this
.
transactions
=
this
.
Reorder
(
this
.
transactions
);
block
.
Transactions
.
AddRange
(
this
.
transactions
);
this
.
transactions
.
Clear
();
}
block
.
UpdateMerkleRoot
();
while
(!
block
.
CheckProofOfWork
(
rpc
.
Network
.
Consensus
))
block
.
Header
.
Nonce
=
++
nonce
;
blocks
.
Add
(
block
);
chain
.
SetTip
(
block
.
Header
);
}
if
(
broadcast
)
await
this
.
BroadcastBlocksAsync
(
blocks
.
ToArray
(),
peer
);
}
return
blocks
.
ToArray
();
}
/// <summary>
/// Get the chain of headers from the peer (thread safe).
/// </summary>
/// <param name="peer">Peer to get chain from.</param>
/// <param name="hashStop">The highest block wanted.</param>
/// <param name="cancellationToken"></param>
/// <returns>The chain of headers.</returns>
private
ConcurrentChain
GetChain
(
INetworkPeer
peer
,
uint256
hashStop
=
null
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
))
{
ConcurrentChain
chain
=
new
ConcurrentChain
(
peer
.
Network
);
this
.
SynchronizeChain
(
peer
,
chain
,
hashStop
,
cancellationToken
);
return
chain
;
}
/// <summary>
/// Synchronize a given Chain to the tip of the given node if its height is higher. (Thread safe).
/// </summary>
/// <param name="peer">Node to synchronize the chain for.</param>
/// <param name="chain">The chain to synchronize.</param>
/// <param name="hashStop">The location until which it synchronize.</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private
IEnumerable
<
ChainedHeader
>
SynchronizeChain
(
INetworkPeer
peer
,
ChainBase
chain
,
uint256
hashStop
=
null
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
))
{
ChainedHeader
oldTip
=
chain
.
Tip
;
List
<
ChainedHeader
>
headers
=
this
.
GetHeadersFromFork
(
peer
,
oldTip
,
hashStop
,
cancellationToken
).
ToList
();
if
(
headers
.
Count
==
0
)
return
new
ChainedHeader
[
0
];
ChainedHeader
newTip
=
headers
[
headers
.
Count
-
1
];
if
(
newTip
.
Height
<=
oldTip
.
Height
)
throw
new
ProtocolException
(
"No tip should have been recieved older than the local one"
);
foreach
(
ChainedHeader
header
in
headers
)
{
if
(!
header
.
Validate
(
peer
.
Network
))
{
throw
new
ProtocolException
(
"A header which does not pass proof of work verification has been received"
);
}
}
chain
.
SetTip
(
newTip
);
return
headers
;
}
private
async
Task
AssertStateAsync
(
INetworkPeer
peer
,
NetworkPeerState
peerState
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
))
{
if
((
peerState
==
NetworkPeerState
.
HandShaked
)
&&
(
peer
.
State
==
NetworkPeerState
.
Connected
))
await
peer
.
VersionHandshakeAsync
(
cancellationToken
);
if
(
peerState
!=
peer
.
State
)
throw
new
InvalidOperationException
(
"Invalid Node state, needed="
+
peerState
+
", current= "
+
this
.
State
);
}
public
IEnumerable
<
ChainedHeader
>
GetHeadersFromFork
(
INetworkPeer
peer
,
ChainedHeader
currentTip
,
uint256
hashStop
=
null
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
))
{
this
.
AssertStateAsync
(
peer
,
NetworkPeerState
.
HandShaked
,
cancellationToken
).
GetAwaiter
().
GetResult
();
using
(
var
listener
=
new
NetworkPeerListener
(
peer
))
{
int
acceptMaxReorgDepth
=
0
;
while
(
true
)
{
// Get before last so, at the end, we should only receive 1 header equals to this one (so we will not have race problems with concurrent GetChains).
BlockLocator
awaited
=
currentTip
.
Previous
==
null
?
currentTip
.
GetLocator
()
:
currentTip
.
Previous
.
GetLocator
();
peer
.
SendMessageAsync
(
new
GetHeadersPayload
()
{
BlockLocators
=
awaited
,
HashStop
=
hashStop
}).
GetAwaiter
().
GetResult
();
while
(
true
)
{
bool
isOurs
=
false
;
HeadersPayload
headers
=
null
;
using
(
var
headersCancel
=
CancellationTokenSource
.
CreateLinkedTokenSource
(
cancellationToken
))
{
headersCancel
.
CancelAfter
(
TimeSpan
.
FromMinutes
(
1.0
));
try
{
headers
=
listener
.
ReceivePayloadAsync
<
HeadersPayload
>(
headersCancel
.
Token
).
GetAwaiter
().
GetResult
();
}
catch
(
OperationCanceledException
)
{
acceptMaxReorgDepth
+=
6
;
if
(
cancellationToken
.
IsCancellationRequested
)
throw
;
// Send a new GetHeaders.
break
;
}
}
// In the special case where the remote node is at height 0 as well as us, then the headers count will be 0.
if
((
headers
.
Headers
.
Count
==
0
)
&&
(
peer
.
PeerVersion
.
StartHeight
==
0
)
&&
(
currentTip
.
HashBlock
==
peer
.
Network
.
GenesisHash
))
yield
break
;
if
((
headers
.
Headers
.
Count
==
1
)
&&
(
headers
.
Headers
[
0
].
GetHash
()
==
currentTip
.
HashBlock
))
yield
break
;
foreach
(
BlockHeader
header
in
headers
.
Headers
)
{
uint256
hash
=
header
.
GetHash
();
if
(
hash
==
currentTip
.
HashBlock
)
continue
;
// The previous headers request timeout, this can arrive in case of big reorg.
if
(
header
.
HashPrevBlock
!=
currentTip
.
HashBlock
)
{
int
reorgDepth
=
0
;
ChainedHeader
tempCurrentTip
=
currentTip
;
while
(
reorgDepth
!=
acceptMaxReorgDepth
&&
tempCurrentTip
!=
null
&&
header
.
HashPrevBlock
!=
tempCurrentTip
.
HashBlock
)
{
reorgDepth
++;
tempCurrentTip
=
tempCurrentTip
.
Previous
;
}
if
(
reorgDepth
!=
acceptMaxReorgDepth
&&
tempCurrentTip
!=
null
)
currentTip
=
tempCurrentTip
;
}
if
(
header
.
HashPrevBlock
==
currentTip
.
HashBlock
)
{
isOurs
=
true
;
currentTip
=
new
ChainedHeader
(
header
,
hash
,
currentTip
);
yield
return
currentTip
;
if
(
currentTip
.
HashBlock
==
hashStop
)
yield
break
;
}
else
break
;
// Not our headers, continue receive.
}
if
(
isOurs
)
break
;
//Go ask for next header.
}
}
}
}
public
bool
AddToStratisMempool
(
Transaction
trx
)
{
var
fullNode
=
(
this
.
runner
as
StratisBitcoinPowRunner
).
FullNode
;
var
state
=
new
MempoolValidationState
(
true
);
return
fullNode
.
MempoolManager
().
Validator
.
AcceptToMemoryPool
(
state
,
trx
).
Result
;
}
public
List
<
uint256
>
GenerateStratisWithMiner
(
int
blockCount
)
{
return
this
.
FullNode
.
Services
.
ServiceProvider
.
GetService
<
IPowMining
>().
GenerateBlocks
(
new
ReserveScript
{
ReserveFullNodeScript
=
this
.
MinerSecret
.
ScriptPubKey
},
(
ulong
)
blockCount
,
uint
.
MaxValue
);
}
[
Obsolete
(
"Please use GenerateStratisWithMiner instead."
)]
public
Block
[]
GenerateStratis
(
int
blockCount
,
List
<
Transaction
>
passedTransactions
=
null
,
bool
broadcast
=
true
)
{
var
fullNode
=
(
this
.
runner
as
StratisBitcoinPowRunner
).
FullNode
;
BitcoinSecret
dest
=
this
.
MinerSecret
;
List
<
Block
>
blocks
=
new
List
<
Block
>();
DateTimeOffset
now
=
this
.
MockTime
==
null
?
DateTimeOffset
.
UtcNow
:
this
.
MockTime
.
Value
;
#if !NOSOCKET
//for (int i = 0; i < blockCount; i++)
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
uint
nonce
=
0
;
Block
block
=
new
Block
();
block
.
Header
.
HashPrevBlock
=
fullNode
.
Chain
.
Tip
.
HashBlock
;
block
.
Header
.
Bits
=
block
.
Header
.
GetWorkRequired
(
fullNode
.
Network
,
fullNode
.
Chain
.
Tip
);
block
.
Header
.
UpdateTime
(
now
,
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
=
this
.
Reorder
(
passedTransactions
);
block
.
Transactions
.
AddRange
(
passedTransactions
);
}
block
.
UpdateMerkleRoot
();
while
(!
block
.
CheckProofOfWork
(
fullNode
.
Network
.
Consensus
))
block
.
Header
.
Nonce
=
++
nonce
;
blocks
.
Add
(
block
);
if
(
broadcast
)
{
uint256
blockHash
=
block
.
GetHash
();
var
newChain
=
new
ChainedHeader
(
block
.
Header
,
blockHash
,
fullNode
.
Chain
.
Tip
);
var
oldTip
=
fullNode
.
Chain
.
SetTip
(
newChain
);
fullNode
.
ConsensusLoop
().
Puller
.
InjectBlock
(
blockHash
,
new
DownloadedBlock
{
Length
=
block
.
GetSerializedSize
(),
Block
=
block
},
CancellationToken
.
None
);
//try
//{
// var blockResult = new BlockResult { Block = block };
// fullNode.ConsensusLoop.AcceptBlock(blockResult);
// // similar logic to what's in the full node code
// if (blockResult.Error == null)
// {
// fullNode.ChainBehaviorState.ConsensusTip = fullNode.ConsensusLoop.Tip;
// //if (fullNode.Chain.Tip.HashBlock == blockResult.ChainedHeader.HashBlock)
// //{
// // var unused = cache.FlushAsync();
// //}
// fullNode.Signals.Blocks.Broadcast(block);
// }
//}
//catch (ConsensusErrorException)
//{
// // set back the old tip
// fullNode.Chain.SetTip(oldTip);
//}
}
}
return
blocks
.
ToArray
();
#endif
}
public
async
Task
BroadcastBlocksAsync
(
Block
[]
blocks
)
{
using
(
INetworkPeer
peer
=
this
.
CreateNetworkPeerClient
())
{
await
peer
.
VersionHandshakeAsync
();
await
this
.
BroadcastBlocksAsync
(
blocks
,
peer
);
}
}
public
async
Task
BroadcastBlocksAsync
(
Block
[]
blocks
,
INetworkPeer
peer
)
{
foreach
(
var
block
in
blocks
)
{
await
peer
.
SendMessageAsync
(
new
InvPayload
(
block
));
await
peer
.
SendMessageAsync
(
new
BlockPayload
(
block
));
}
await
this
.
PingPongAsync
(
peer
);
}
public
Block
[]
FindBlock
(
int
blockCount
=
1
,
bool
includeMempool
=
true
)
{
this
.
SelectMempoolTransactions
();
return
this
.
GenerateAsync
(
blockCount
,
includeMempool
).
GetAwaiter
().
GetResult
();
}
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
List
<
Transaction
>
Reorder
(
List
<
Transaction
>
transactions
)
{
if
(
transactions
.
Count
==
0
)
return
transactions
;
var
result
=
new
List
<
Transaction
>();
var
dictionary
=
transactions
.
ToDictionary
(
t
=>
t
.
GetHash
(),
t
=>
new
TransactionNode
(
t
));
foreach
(
var
transaction
in
dictionary
.
Select
(
d
=>
d
.
Value
))
{
foreach
(
var
input
in
transaction
.
Transaction
.
Inputs
)
{
var
node
=
dictionary
.
TryGet
(
input
.
PrevOut
.
Hash
);
if
(
node
!=
null
)
{
transaction
.
DependsOn
.
Add
(
node
);
}
}
}
while
(
dictionary
.
Count
!=
0
)
{
foreach
(
var
node
in
dictionary
.
Select
(
d
=>
d
.
Value
).
ToList
())
{
foreach
(
var
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
;
}
private
BitcoinSecret
GetFirstSecret
(
RPCClient
rpc
)
{
if
(
this
.
MinerSecret
!=
null
)
return
this
.
MinerSecret
;
var
dest
=
rpc
.
ListSecrets
().
FirstOrDefault
();
if
(
dest
==
null
)
{
var
address
=
rpc
.
GetNewAddress
();
dest
=
rpc
.
DumpPrivKey
(
address
);
}
return
dest
;
}
}
}
Sources/Stratis.Bitcoin.IntegrationTests/EnvironmentMockUpHelpers/InitialBlockDownloadStateMock.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
NBitcoin
;
using
Stratis.Bitcoin.Base
;
using
Stratis.Bitcoin.Configuration
;
using
Stratis.Bitcoin.Features.Consensus
;
using
Stratis.Bitcoin.Interfaces
;
using
Stratis.Bitcoin.Utilities
;
namespace
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
{
public
class
InitialBlockDownloadStateMock
:
IInitialBlockDownloadState
{
/// <summary>Time until IBD state can be checked.</summary>
private
DateTime
lockIbdUntil
;
/// <summary>A cached result of the IBD method.</summary>
private
bool
blockDownloadState
;
/// <summary>A provider of the date and time.</summary>
protected
readonly
IDateTimeProvider
dateTimeProvider
;
private
readonly
InitialBlockDownloadState
innerBlockDownloadState
;
public
InitialBlockDownloadStateMock
(
IChainState
chainState
,
Network
network
,
NodeSettings
nodeSettings
,
ICheckpoints
checkpoints
)
{
this
.
lockIbdUntil
=
DateTime
.
MinValue
;
this
.
dateTimeProvider
=
DateTimeProvider
.
Default
;
this
.
innerBlockDownloadState
=
new
InitialBlockDownloadState
(
chainState
,
network
,
nodeSettings
,
checkpoints
);
}
public
bool
IsInitialBlockDownload
()
{
if
(
this
.
lockIbdUntil
>=
this
.
dateTimeProvider
.
GetUtcNow
())
return
this
.
blockDownloadState
;
return
this
.
innerBlockDownloadState
.
IsInitialBlockDownload
();
}
/// <summary>
/// Sets last IBD status update time and result.
/// </summary>
/// <param name="blockDownloadState">New value for the IBD status, <c>true</c> means the node is considered in IBD.</param>
/// <param name="lockIbdUntil">Time until IBD state won't be changed.</param>
public
void
SetIsInitialBlockDownload
(
bool
blockDownloadState
,
DateTime
lockIbdUntil
)
{
this
.
lockIbdUntil
=
lockIbdUntil
;
this
.
blockDownloadState
=
blockDownloadState
;
}
}
}
Sources/Stratis.Bitcoin.IntegrationTests/EnvironmentMockUpHelpers/NetworkSimulator.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Runtime.CompilerServices
;
using
System.Threading
;
using
NBitcoin
;
using
Stratis.Bitcoin.Features.Wallet
;
namespace
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
{
public
class
NetworkSimulator
:
IDisposable
{
public
List
<
CoreNode
>
Nodes
{
get
;
private
set
;
}
private
NodeBuilder
nodeBuilder
;
public
NetworkSimulator
([
CallerMemberName
]
string
caller
=
null
)
{
this
.
nodeBuilder
=
NodeBuilder
.
Create
(
caller
:
caller
);
}
public
void
Initialize
(
int
nodesCount
)
{
this
.
Nodes
=
new
List
<
CoreNode
>();
for
(
int
i
=
0
;
i
<
nodesCount
;
++
i
)
{
CoreNode
node
=
this
.
nodeBuilder
.
CreateStratisPowNode
(
true
);
node
.
NotInIBD
();
node
.
FullNode
.
WalletManager
().
CreateWallet
(
"dummyPassword"
,
"dummyWallet"
);
var
address
=
node
.
FullNode
.
WalletManager
().
GetUnusedAddress
(
new
WalletAccountReference
(
"dummyWallet"
,
"account 0"
));
var
wallet
=
node
.
FullNode
.
WalletManager
().
GetWalletByName
(
"dummyWallet"
);
var
key
=
wallet
.
GetExtendedPrivateKeyForAddress
(
"dummyPassword"
,
address
).
PrivateKey
;
node
.
SetDummyMinerSecret
(
new
BitcoinSecret
(
key
,
node
.
FullNode
.
Network
));
this
.
Nodes
.
Add
(
node
);
}
}
public
bool
AreAllNodesAtSameHeight
()
{
return
this
.
Nodes
.
Select
(
i
=>
i
.
FullNode
.
Chain
.
Height
).
Distinct
().
Count
()
==
1
;
}
public
void
Dispose
()
{
this
.
nodeBuilder
.
Dispose
();
}
public
bool
DidAllNodesReachHeight
(
int
height
)
{
return
this
.
Nodes
.
All
(
i
=>
i
.
FullNode
.
Chain
.
Height
>=
height
);
}
public
void
MakeSureEachNodeCanMineAndSync
()
{
foreach
(
var
node
in
this
.
Nodes
)
{
Thread
.
Sleep
(
1000
);
var
currentHeight
=
node
.
FullNode
.
Chain
.
Height
;
node
.
GenerateStratisWithMiner
(
1
);
TestHelper
.
WaitLoop
(()
=>
TestHelper
.
IsNodeSynced
(
node
));
TestHelper
.
WaitLoop
(
new
Func
<
bool
>(
delegate
{
return
node
.
FullNode
.
Chain
.
Height
==
currentHeight
+
1
;
}));
TestHelper
.
WaitLoop
(
new
Func
<
bool
>(
delegate
{
return
AreAllNodesAtSameHeight
();
}));
}
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/EnvironmentMockUpHelpers/NodeBuilder.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Collections.Generic
;
using
System.Diagnostics
;
using
System.IO
;
using
System.IO.Compression
;
using
System.Linq
;
using
System.Net.Http
;
using
System.Runtime.CompilerServices
;
using
System.Runtime.InteropServices
;
using
System.Text
;
using
System.Threading
;
using
NBitcoin
;
using
Stratis.Bitcoin.Features.BlockStore
;
using
Stratis.Bitcoin.Features.Consensus
;
using
Stratis.Bitcoin.Features.Consensus.CoinViews
;
using
Stratis.Bitcoin.Features.Consensus.Interfaces
;
using
Stratis.Bitcoin.Features.MemoryPool
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.Features.Wallet.Interfaces
;
namespace
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
{
internal
static
class
FullNodeExt
{
public
static
WalletManager
WalletManager
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
IWalletManager
>()
as
WalletManager
;
}
public
static
WalletTransactionHandler
WalletTransactionHandler
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
IWalletTransactionHandler
>()
as
WalletTransactionHandler
;
}
public
static
ConsensusLoop
ConsensusLoop
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
IConsensusLoop
>()
as
ConsensusLoop
;
}
public
static
CoinView
CoinView
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
CoinView
>();
}
public
static
MempoolManager
MempoolManager
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
MempoolManager
>();
}
public
static
BlockStoreManager
BlockStoreManager
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
BlockStoreManager
>();
}
public
static
ChainedHeader
HighestPersistedBlock
(
this
FullNode
fullNode
)
{
return
fullNode
.
NodeService
<
IBlockRepository
>().
HighestPersistedBlock
;
}
}
public
enum
CoreNodeState
{
Stopped
,
Starting
,
Running
,
Killed
}
public
class
NodeConfigParameters
:
Dictionary
<
string
,
string
>
{
public
void
Import
(
NodeConfigParameters
configParameters
)
{
foreach
(
var
kv
in
configParameters
)
{
if
(!
this
.
ContainsKey
(
kv
.
Key
))
this
.
Add
(
kv
.
Key
,
kv
.
Value
);
}
}
public
override
string
ToString
()
{
StringBuilder
builder
=
new
StringBuilder
();
foreach
(
var
kv
in
this
)
builder
.
AppendLine
(
kv
.
Key
+
"="
+
kv
.
Value
);
return
builder
.
ToString
();
}
}
public
class
NodeBuilder
:
IDisposable
{
public
string
BitcoinD
{
get
;
}
public
List
<
CoreNode
>
Nodes
{
get
;
}
public
NodeConfigParameters
ConfigParameters
{
get
;
}
private
int
lastDataFolderIndex
;
private
string
rootFolder
;
public
NodeBuilder
(
string
rootFolder
,
string
bitcoindPath
)
{
this
.
lastDataFolderIndex
=
0
;
this
.
Nodes
=
new
List
<
CoreNode
>();
this
.
ConfigParameters
=
new
NodeConfigParameters
();
this
.
rootFolder
=
rootFolder
;
this
.
BitcoinD
=
bitcoindPath
;
}
public
static
NodeBuilder
Create
([
CallerMemberName
]
string
caller
=
null
,
string
version
=
"0.13.1"
)
{
KillAnyBitcoinInstances
();
caller
=
Path
.
Combine
(
"TestData"
,
caller
);
CreateTestFolder
(
caller
);
return
new
NodeBuilder
(
caller
,
DownloadBitcoinCore
(
version
));
}
private
static
string
DownloadBitcoinCore
(
string
version
)
{
//is a file
if
(
version
.
Length
>=
2
&&
version
[
1
]
==
':'
)
{
return
version
;
}
if
(
RuntimeInformation
.
IsOSPlatform
(
OSPlatform
.
Windows
))
{
var
bitcoind
=
string
.
Format
(
"TestData/bitcoin-{0}/bin/bitcoind.exe"
,
version
);
if
(
File
.
Exists
(
bitcoind
))
return
bitcoind
;
var
zip
=
string
.
Format
(
"TestData/bitcoin-{0}-win32.zip"
,
version
);
string
url
=
string
.
Format
(
"https://bitcoin.org/bin/bitcoin-core-{0}/"
+
Path
.
GetFileName
(
zip
),
version
);
var
client
=
new
HttpClient
{
Timeout
=
TimeSpan
.
FromMinutes
(
10.0
)
};
var
data
=
client
.
GetByteArrayAsync
(
url
).
GetAwaiter
().
GetResult
();
File
.
WriteAllBytes
(
zip
,
data
);
ZipFile
.
ExtractToDirectory
(
zip
,
new
FileInfo
(
zip
).
Directory
.
FullName
);
return
bitcoind
;
}
else
{
string
bitcoind
=
string
.
Format
(
"TestData/bitcoin-{0}/bin/bitcoind"
,
version
);
if
(
File
.
Exists
(
bitcoind
))
return
bitcoind
;
var
zip
=
RuntimeInformation
.
IsOSPlatform
(
OSPlatform
.
Linux
)
?
string
.
Format
(
"TestData/bitcoin-{0}-x86_64-linux-gnu.tar.gz"
,
version
)
:
string
.
Format
(
"TestData/bitcoin-{0}-osx64.tar.gz"
,
version
);
string
url
=
string
.
Format
(
"https://bitcoin.org/bin/bitcoin-core-{0}/"
+
Path
.
GetFileName
(
zip
),
version
);
var
client
=
new
HttpClient
{
Timeout
=
TimeSpan
.
FromMinutes
(
10.0
)
};
var
data
=
client
.
GetByteArrayAsync
(
url
).
GetAwaiter
().
GetResult
();
File
.
WriteAllBytes
(
zip
,
data
);
Process
.
Start
(
"tar"
,
"-zxvf "
+
zip
+
" -C TestData"
);
return
bitcoind
;
}
}
private
CoreNode
CreateNode
(
NodeRunner
runner
,
Network
network
,
bool
start
,
string
configFile
=
"bitcoin.conf"
)
{
var
node
=
new
CoreNode
(
runner
,
this
,
network
,
configFile
);
this
.
Nodes
.
Add
(
node
);
if
(
start
)
node
.
Start
();
return
node
;
}
public
CoreNode
CreateBitcoinCoreNode
(
bool
start
=
false
)
{
return
CreateNode
(
new
BitcoinCoreRunner
(
this
.
GetNextDataFolderName
(),
this
.
BitcoinD
),
Network
.
RegTest
,
start
);
}
public
CoreNode
CreateStratisPowNode
(
bool
start
=
false
)
{
return
CreateNode
(
new
StratisBitcoinPowRunner
(
this
.
GetNextDataFolderName
()),
Network
.
RegTest
,
start
);
}
public
CoreNode
CreateStratisPowMiningNode
(
bool
start
=
false
)
{
return
CreateNode
(
new
StratisProofOfWorkMiningNode
(
this
.
GetNextDataFolderName
()),
Network
.
RegTest
,
start
,
"stratis.conf"
);
}
public
CoreNode
CreateStratisPosNode
(
bool
start
=
false
)
{
return
CreateNode
(
new
StratisBitcoinPosRunner
(
this
.
GetNextDataFolderName
()),
Network
.
RegTest
,
start
,
"stratis.conf"
);
}
public
CoreNode
CreateStratisPosApiNode
(
bool
start
=
false
)
{
return
CreateNode
(
new
StratisPosApiRunner
(
this
.
GetNextDataFolderName
()),
Network
.
RegTest
,
start
,
"stratis.conf"
);
}
public
CoreNode
CloneStratisNode
(
CoreNode
cloneNode
)
{
var
node
=
new
CoreNode
(
new
StratisBitcoinPowRunner
(
cloneNode
.
FullNode
.
Settings
.
DataFolder
.
RootPath
),
this
,
Network
.
RegTest
,
"bitcoin.conf"
);
this
.
Nodes
.
Add
(
node
);
this
.
Nodes
.
Remove
(
cloneNode
);
return
node
;
}
private
string
GetNextDataFolderName
()
{
var
dataFolderName
=
Path
.
Combine
(
this
.
rootFolder
,
this
.
lastDataFolderIndex
.
ToString
());
this
.
lastDataFolderIndex
++;
return
dataFolderName
;
}
public
void
StartAll
()
{
foreach
(
var
node
in
this
.
Nodes
.
Where
(
n
=>
n
.
State
==
CoreNodeState
.
Stopped
))
{
node
.
Start
();
}
}
public
void
Dispose
()
{
foreach
(
var
node
in
this
.
Nodes
)
node
.
Kill
();
KillAnyBitcoinInstances
();
}
internal
static
void
KillAnyBitcoinInstances
()
{
while
(
true
)
{
var
bitcoinDProcesses
=
Process
.
GetProcessesByName
(
"bitcoind"
);
var
applicableBitcoinDProcesses
=
bitcoinDProcesses
.
Where
(
b
=>
b
.
MainModule
.
FileName
.
Contains
(
"Stratis.Bitcoin.IntegrationTests"
));
if
(!
applicableBitcoinDProcesses
.
Any
())
break
;
foreach
(
var
process
in
applicableBitcoinDProcesses
)
{
process
.
Kill
();
Thread
.
Sleep
(
1000
);
}
}
}
internal
static
void
CreateTestFolder
(
string
folderName
)
{
var
deleteAttempts
=
0
;
while
(
deleteAttempts
<
50
)
{
if
(
Directory
.
Exists
(
folderName
))
{
try
{
Directory
.
Delete
(
folderName
,
true
);
break
;
}
catch
{
deleteAttempts
++;
Thread
.
Sleep
(
200
);
}
}
else
break
;
}
if
(
deleteAttempts
>=
50
)
throw
new
Exception
(
string
.
Format
(
"The test folder: {0} could not be created."
,
folderName
));
Directory
.
CreateDirectory
(
folderName
);
}
internal
static
void
CreateDataFolder
(
string
dataFolder
)
{
if
(!
Directory
.
Exists
(
dataFolder
))
Directory
.
CreateDirectory
(
dataFolder
);
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/EnvironmentMockUpHelpers/NodeRunners.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Diagnostics
;
using
System.IO
;
using
NBitcoin
;
using
NBitcoin.Protocol
;
using
Stratis.Bitcoin.Builder
;
using
Stratis.Bitcoin.Configuration
;
using
Stratis.Bitcoin.Features.Api
;
using
Stratis.Bitcoin.Features.BlockStore
;
using
Stratis.Bitcoin.Features.Consensus
;
using
Stratis.Bitcoin.Features.MemoryPool
;
using
Stratis.Bitcoin.Features.Miner
;
using
Stratis.Bitcoin.Features.RPC
;
using
Stratis.Bitcoin.Features.Wallet
;
namespace
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
{
public
class
BitcoinCoreRunner
:
NodeRunner
{
private
string
bitcoinD
;
public
BitcoinCoreRunner
(
string
dataDir
,
string
bitcoinD
)
:
base
(
dataDir
)
{
this
.
bitcoinD
=
bitcoinD
;
}
private
Process
process
;
public
new
bool
IsDisposed
{
get
{
return
this
.
process
==
null
&&
this
.
process
.
HasExited
;
}
}
public
new
void
Kill
()
{
if
(!
this
.
IsDisposed
)
{
this
.
process
.
Kill
();
this
.
process
.
WaitForExit
();
}
}
public
override
void
OnStart
()
{
this
.
process
=
Process
.
Start
(
new
FileInfo
(
this
.
bitcoinD
).
FullName
,
$"-conf=bitcoin.conf -datadir=
{
this
.
DataFolder
}
-debug=net"
);
}
public
override
void
BuildNode
()
{
}
}
public
abstract
class
NodeRunner
{
public
readonly
string
DataFolder
;
public
bool
IsDisposed
=>
this
.
FullNode
.
State
==
FullNodeState
.
Disposed
;
public
FullNode
FullNode
{
get
;
set
;
}
protected
NodeRunner
(
string
dataDir
)
{
this
.
DataFolder
=
dataDir
;
}
public
abstract
void
BuildNode
();
public
abstract
void
OnStart
();
public
void
Kill
()
{
this
.
FullNode
?.
Dispose
();
}
public
void
Start
()
{
BuildNode
();
OnStart
();
}
}
public
sealed
class
StratisBitcoinPosRunner
:
NodeRunner
{
public
StratisBitcoinPosRunner
(
string
dataDir
)
:
base
(
dataDir
)
{
}
public
override
void
BuildNode
()
{
var
settings
=
new
NodeSettings
(
Network
.
StratisRegTest
,
ProtocolVersion
.
ALT_PROTOCOL_VERSION
,
args
:
new
string
[]
{
"-conf=stratis.conf"
,
"-datadir="
+
this
.
DataFolder
},
loadConfiguration
:
false
);
this
.
FullNode
=
(
FullNode
)
new
FullNodeBuilder
()
.
UseNodeSettings
(
settings
)
.
UsePosConsensus
()
.
UseBlockStore
()
.
UseMempool
()
.
UseWallet
()
.
AddPowPosMining
()
.
AddRPC
()
.
MockIBD
()
.
SubstituteDateTimeProviderFor
<
MiningFeature
>()
.
Build
();
}
public
override
void
OnStart
()
{
this
.
FullNode
.
Start
();
}
/// <summary>
/// Builds a node with POS miner and RPC enabled.
/// </summary>
/// <param name="dataDir">Data directory that the node should use.</param>
/// <returns>Interface to the newly built node.</returns>
/// <remarks>Currently the node built here does not actually stake as it has no coins in the wallet,
/// but all the features required for it are enabled.</remarks>
public
static
IFullNode
BuildStakingNode
(
string
dataDir
,
bool
staking
=
true
)
{
var
nodeSettings
=
new
NodeSettings
(
args
:
new
string
[]
{
$"-datadir=
{
dataDir
}
"
,
$"-stake=
{(
staking
?
1
:
0
)}
"
,
"-walletname=dummy"
,
"-walletpassword=dummy"
},
loadConfiguration
:
false
);
var
fullNodeBuilder
=
new
FullNodeBuilder
(
nodeSettings
);
IFullNode
fullNode
=
fullNodeBuilder
.
UsePosConsensus
()
.
UseBlockStore
()
.
UseMempool
()
.
UseWallet
()
.
AddPowPosMining
()
.
AddRPC
()
.
MockIBD
()
.
Build
();
return
fullNode
;
}
}
public
sealed
class
StratisPosApiRunner
:
NodeRunner
{
public
StratisPosApiRunner
(
string
dataDir
)
:
base
(
dataDir
)
{
}
public
override
void
BuildNode
()
{
var
settings
=
new
NodeSettings
(
Network
.
StratisRegTest
,
ProtocolVersion
.
ALT_PROTOCOL_VERSION
,
args
:
new
string
[]
{
"-conf=stratis.conf"
,
"-datadir="
+
this
.
DataFolder
},
loadConfiguration
:
false
);
this
.
FullNode
=
(
FullNode
)
new
FullNodeBuilder
()
.
UseNodeSettings
(
settings
)
.
UsePosConsensus
()
.
UseBlockStore
()
.
UseMempool
()
.
AddPowPosMining
()
.
UseWallet
()
.
UseApi
()
.
AddRPC
()
.
Build
();
}
public
override
void
OnStart
()
{
this
.
FullNode
.
Start
();
}
}
public
sealed
class
StratisBitcoinPowRunner
:
NodeRunner
{
public
StratisBitcoinPowRunner
(
string
dataDir
)
:
base
(
dataDir
)
{
}
public
override
void
BuildNode
()
{
var
settings
=
new
NodeSettings
(
args
:
new
string
[]
{
"-conf=bitcoin.conf"
,
"-datadir="
+
this
.
DataFolder
},
loadConfiguration
:
false
);
this
.
FullNode
=
(
FullNode
)
new
FullNodeBuilder
()
.
UseNodeSettings
(
settings
)
.
UsePowConsensus
()
.
UseBlockStore
()
.
UseMempool
()
.
AddMining
()
.
UseWallet
()
.
AddRPC
()
.
MockIBD
()
.
Build
();
}
public
override
void
OnStart
()
{
this
.
FullNode
.
Start
();
}
}
public
sealed
class
StratisProofOfWorkMiningNode
:
NodeRunner
{
public
StratisProofOfWorkMiningNode
(
string
dataDir
)
:
base
(
dataDir
)
{
}
public
override
void
BuildNode
()
{
var
settings
=
new
NodeSettings
(
Network
.
StratisRegTest
,
ProtocolVersion
.
ALT_PROTOCOL_VERSION
,
args
:
new
string
[]
{
"-conf=stratis.conf"
,
"-datadir="
+
this
.
DataFolder
},
loadConfiguration
:
false
);
this
.
FullNode
=
(
FullNode
)
new
FullNodeBuilder
()
.
UseNodeSettings
(
settings
)
.
UsePosConsensus
()
.
UseBlockStore
()
.
UseMempool
()
.
AddMining
()
.
UseWallet
()
.
AddRPC
()
.
MockIBD
()
.
SubstituteDateTimeProviderFor
<
MiningFeature
>()
.
Build
();
}
public
override
void
OnStart
()
{
this
.
FullNode
.
Start
();
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/Extensions/CoreNodeExtensions.cs
deleted
100644 → 0
View file @
3c8c9867
using
System.Linq
;
using
NBitcoin
;
using
Stratis.Bitcoin.Features.Consensus.Interfaces
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
;
namespace
Stratis.Bitcoin.IntegrationTests
{
public
static
class
CoreNodeExtensions
{
public
static
Money
GetProofOfWorkRewardForMinedBlocks
(
this
CoreNode
node
,
int
numberOfBlocks
)
{
var
powValidator
=
node
.
FullNode
.
NodeService
<
IPowConsensusValidator
>();
var
startBlock
=
node
.
FullNode
.
Chain
.
Height
-
numberOfBlocks
+
1
;
var
totalReward
=
Enumerable
.
Range
(
startBlock
,
numberOfBlocks
).
Sum
(
p
=>
powValidator
.
GetProofOfWorkReward
(
p
));
return
totalReward
;
}
public
static
Money
WalletBalance
(
this
CoreNode
node
,
string
walletName
)
{
return
node
.
FullNode
.
WalletManager
().
GetSpendableTransactionsInWallet
(
walletName
).
Sum
(
s
=>
s
.
Transaction
.
Amount
);
}
public
static
int
?
WalletHeight
(
this
CoreNode
node
,
string
walletName
)
{
return
node
.
FullNode
.
WalletManager
().
GetSpendableTransactionsInWallet
(
walletName
).
First
().
Transaction
.
BlockHeight
;
}
public
static
int
WalletSpendableTransactionCount
(
this
CoreNode
node
,
string
walletName
)
{
return
node
.
FullNode
.
WalletManager
().
GetSpendableTransactionsInWallet
(
walletName
).
Count
();
}
public
static
Money
GetFee
(
this
CoreNode
node
,
TransactionBuildContext
transactionBuildContext
)
{
return
node
.
FullNode
.
WalletTransactionHandler
().
EstimateFee
(
transactionBuildContext
);
}
}
}
Sources/Stratis.Bitcoin.IntegrationTests/Extensions/FullNodeTestBuilderExtension.cs
deleted
100644 → 0
View file @
3c8c9867
using
System.Linq
;
using
Microsoft.Extensions.DependencyInjection
;
using
Stratis.Bitcoin.Builder
;
using
Stratis.Bitcoin.Builder.Feature
;
using
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
;
using
Stratis.Bitcoin.Interfaces
;
using
Stratis.Bitcoin.Utilities
;
namespace
Stratis.Bitcoin.IntegrationTests
{
public
static
class
FullNodeTestBuilderExtension
{
/// <summary>
/// Substitute the <see cref="IDateTimeProvider"/> for a given feature.
/// </summary>
/// <typeparam name="T">The feature to substitute the provider for.</typeparam>
public
static
IFullNodeBuilder
SubstituteDateTimeProviderFor
<
T
>(
this
IFullNodeBuilder
fullNodeBuilder
)
{
fullNodeBuilder
.
ConfigureFeature
(
features
=>
{
var
feature
=
features
.
FeatureRegistrations
.
FirstOrDefault
(
f
=>
f
.
FeatureType
==
typeof
(
T
));
if
(
feature
!=
null
)
{
feature
.
FeatureServices
(
services
=>
{
ServiceDescriptor
service
=
services
.
FirstOrDefault
(
s
=>
s
.
ServiceType
==
typeof
(
IDateTimeProvider
));
if
(
service
!=
null
)
services
.
Remove
(
service
);
services
.
AddSingleton
<
IDateTimeProvider
,
GenerateCoinsFastDateTimeProvider
>();
});
}
});
return
fullNodeBuilder
;
}
public
static
IFullNodeBuilder
MockIBD
(
this
IFullNodeBuilder
fullNodeBuilder
)
{
fullNodeBuilder
.
ConfigureFeature
(
features
=>
{
foreach
(
IFeatureRegistration
feature
in
features
.
FeatureRegistrations
)
{
feature
.
FeatureServices
(
services
=>
{
// Get default IBD implementation and replace it with the mock.
ServiceDescriptor
ibdService
=
services
.
FirstOrDefault
(
x
=>
x
.
ServiceType
==
typeof
(
IInitialBlockDownloadState
));
if
(
ibdService
!=
null
)
{
services
.
Remove
(
ibdService
);
services
.
AddSingleton
<
IInitialBlockDownloadState
,
InitialBlockDownloadStateMock
>();
}
});
}
});
return
fullNodeBuilder
;
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/SharedSteps.cs
deleted
100644 → 0
View file @
3c8c9867
using
System.Collections.Generic
;
using
System.Linq
;
using
FluentAssertions
;
using
NBitcoin
;
using
Stratis.Bitcoin.Features.Consensus
;
using
Stratis.Bitcoin.Features.Wallet
;
using
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
;
namespace
Stratis.Bitcoin.IntegrationTests
{
public
class
SharedSteps
{
public
static
TransactionBuildContext
CreateTransactionBuildContext
(
string
sendingWalletName
,
string
sendingAccountName
,
string
sendingPassword
,
ICollection
<
Recipient
>
recipients
,
FeeType
feeType
,
int
minConfirmations
)
{
return
new
TransactionBuildContext
(
new
WalletAccountReference
(
sendingWalletName
,
sendingAccountName
),
recipients
.
ToList
(),
sendingPassword
)
{
MinConfirmations
=
minConfirmations
,
FeeType
=
feeType
};
}
public
void
MineBlocks
(
int
blockCount
,
CoreNode
node
,
string
accountName
,
string
toWalletName
,
string
withPassword
,
long
expectedFees
=
0
)
{
this
.
WaitForNodeToSync
(
node
);
var
address
=
node
.
FullNode
.
WalletManager
().
GetUnusedAddress
(
new
WalletAccountReference
(
toWalletName
,
accountName
));
var
balanceBeforeMining
=
node
.
FullNode
.
WalletManager
()
.
GetSpendableTransactionsInWallet
(
toWalletName
)
.
Where
(
x
=>
x
.
Address
==
address
)
.
Sum
(
s
=>
s
.
Transaction
.
Amount
);
var
wallet
=
node
.
FullNode
.
WalletManager
().
GetWalletByName
(
toWalletName
);
var
extendedPrivateKey
=
wallet
.
GetExtendedPrivateKeyForAddress
(
withPassword
,
address
).
PrivateKey
;
node
.
SetDummyMinerSecret
(
new
BitcoinSecret
(
extendedPrivateKey
,
node
.
FullNode
.
Network
));
node
.
GenerateStratisWithMiner
(
blockCount
);
var
balanceAfterMining
=
node
.
FullNode
.
WalletManager
()
.
GetSpendableTransactionsInWallet
(
toWalletName
)
.
Where
(
x
=>
x
.
Address
==
address
)
.
Sum
(
s
=>
s
.
Transaction
.
Amount
);
var
balanceIncrease
=
balanceAfterMining
-
balanceBeforeMining
;
this
.
WaitForNodeToSync
(
node
);
balanceIncrease
.
Should
().
Be
(
node
.
GetProofOfWorkRewardForMinedBlocks
(
blockCount
)
+
expectedFees
);
}
public
void
MinePremineBlocks
(
CoreNode
node
,
string
walletName
,
string
walletAccount
,
string
walletPassword
)
{
this
.
WaitForNodeToSync
(
node
);
var
unusedAddress
=
node
.
FullNode
.
WalletManager
().
GetUnusedAddress
(
new
WalletAccountReference
(
walletName
,
walletAccount
));
var
wallet
=
node
.
FullNode
.
WalletManager
().
GetWalletByName
(
walletName
);
var
extendedPrivateKey
=
wallet
.
GetExtendedPrivateKeyForAddress
(
walletPassword
,
unusedAddress
).
PrivateKey
;
node
.
SetDummyMinerSecret
(
new
BitcoinSecret
(
extendedPrivateKey
,
node
.
FullNode
.
Network
));
node
.
GenerateStratisWithMiner
(
2
);
this
.
WaitForNodeToSync
(
node
);
var
spendable
=
node
.
FullNode
.
WalletManager
().
GetSpendableTransactionsInWallet
(
walletName
);
var
amountShouldBe
=
node
.
FullNode
.
Network
.
Consensus
.
Option
<
PosConsensusOptions
>().
PremineReward
+
node
.
FullNode
.
Network
.
Consensus
.
Option
<
PosConsensusOptions
>().
ProofOfWorkReward
;
spendable
.
Sum
(
s
=>
s
.
Transaction
.
Amount
).
Should
().
Be
(
amountShouldBe
);
}
public
void
WaitForNodeToSync
(
params
CoreNode
[]
nodes
)
{
nodes
.
ToList
().
ForEach
(
n
=>
TestHelper
.
WaitLoop
(()
=>
TestHelper
.
IsNodeSynced
(
n
)));
nodes
.
Skip
(
1
).
ToList
().
ForEach
(
n
=>
TestHelper
.
WaitLoop
(()
=>
TestHelper
.
AreNodesSynced
(
nodes
.
First
(),
n
)));
}
}
}
\ No newline at end of file
Sources/Stratis.Bitcoin.IntegrationTests/Stratis.Bitcoin.IntegrationTests.csproj
View file @
1be933f6
...
...
@@ -67,4 +67,9 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Builders\" />
<Folder Include="Extensions\" />
</ItemGroup>
</Project>
Sources/Stratis.Bitcoin.IntegrationTests/TestHelper.cs
deleted
100644 → 0
View file @
3c8c9867
using
System
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Threading
;
using
Stratis.Bitcoin.Base
;
using
Stratis.Bitcoin.IntegrationTests.EnvironmentMockUpHelpers
;
namespace
Stratis.Bitcoin.IntegrationTests
{
public
class
TestHelper
{
public
static
void
WaitLoop
(
Func
<
bool
>
act
)
{
var
cancel
=
new
CancellationTokenSource
(
Debugger
.
IsAttached
?
15
*
60
*
1000
:
30
*
1000
);
while
(!
act
())
{
cancel
.
Token
.
ThrowIfCancellationRequested
();
//Thread.Sleep(50);
}
}
public
static
bool
AreNodesSyncedTemp
(
CoreNode
node1
,
FullNode
node2
)
{
if
(
node1
.
FullNode
.
Chain
.
Tip
.
HashBlock
!=
node2
.
Chain
.
Tip
.
HashBlock
)
return
false
;
if
(
node1
.
FullNode
.
ChainBehaviorState
.
ConsensusTip
.
HashBlock
!=
node2
.
ChainBehaviorState
.
ConsensusTip
.
HashBlock
)
return
false
;
if
(
node1
.
FullNode
.
GetBlockStoreTip
().
HashBlock
!=
node2
.
GetBlockStoreTip
().
HashBlock
)
return
false
;
if
(
node1
.
FullNode
.
MempoolManager
().
InfoAll
().
Count
!=
node2
.
MempoolManager
().
InfoAll
().
Count
)
return
false
;
if
(
node1
.
FullNode
.
WalletManager
().
WalletTipHash
!=
node2
.
WalletManager
().
WalletTipHash
)
return
false
;
//if (node1.CreateRPCClient().GetBestBlockHash() != node2.CreateRPCClient().GetBestBlockHash()) return false;
return
true
;
}
public
static
bool
AreNodesSynced
(
CoreNode
node1
,
CoreNode
node2
)
{
if
(
node1
.
FullNode
.
Chain
.
Tip
.
HashBlock
!=
node2
.
FullNode
.
Chain
.
Tip
.
HashBlock
)
return
false
;
if
(
node1
.
FullNode
.
ChainBehaviorState
.
ConsensusTip
.
HashBlock
!=
node2
.
FullNode
.
ChainBehaviorState
.
ConsensusTip
.
HashBlock
)
return
false
;
if
(
node1
.
FullNode
.
HighestPersistedBlock
().
HashBlock
!=
node2
.
FullNode
.
HighestPersistedBlock
().
HashBlock
)
return
false
;
if
(
node1
.
FullNode
.
MempoolManager
().
InfoAll
().
Count
!=
node2
.
FullNode
.
MempoolManager
().
InfoAll
().
Count
)
return
false
;
if
(
node1
.
FullNode
.
WalletManager
().
WalletTipHash
!=
node2
.
FullNode
.
WalletManager
().
WalletTipHash
)
return
false
;
if
(
node1
.
CreateRPCClient
().
GetBestBlockHash
()
!=
node2
.
CreateRPCClient
().
GetBestBlockHash
())
return
false
;
return
true
;
}
public
static
bool
IsNodeSynced
(
CoreNode
node
)
{
if
(
node
.
FullNode
.
Chain
.
Tip
.
HashBlock
!=
node
.
FullNode
.
ChainBehaviorState
.
ConsensusTip
.
HashBlock
)
return
false
;
if
(
node
.
FullNode
.
Chain
.
Tip
.
HashBlock
!=
node
.
FullNode
.
HighestPersistedBlock
().
HashBlock
)
return
false
;
if
(
node
.
FullNode
.
Chain
.
Tip
.
HashBlock
!=
node
.
FullNode
.
WalletManager
().
WalletTipHash
)
return
false
;
return
true
;
}
public
static
void
TriggerSync
(
CoreNode
node
)
{
foreach
(
var
connectedPeer
in
node
.
FullNode
.
ConnectionManager
.
ConnectedPeers
)
connectedPeer
.
Behavior
<
ChainHeadersBehavior
>().
TrySyncAsync
().
GetAwaiter
().
GetResult
();
}
public
static
bool
IsNodeConnected
(
CoreNode
node
)
{
if
(
node
.
FullNode
.
ConnectionManager
.
ConnectedPeers
.
Any
())
return
true
;
return
false
;
}
}
}
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