Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
Breeze
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
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
Breeze
Commits
73763b96
Commit
73763b96
authored
Apr 21, 2017
by
Jeremy Bokobza
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
import of HBitcoin's Tracker and its dependencies
parent
c5350c48
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1150 additions
and
0 deletions
+1150
-0
Breeze.Wallet.csproj
Breeze/src/Breeze.Wallet/Breeze.Wallet.csproj
+1
-0
ConcurrentObservableDictionary.cs
.../src/Breeze.Wallet/Temp/ConcurrentObservableDictionary.cs
+234
-0
ConcurrentObservableHashSet.cs
Breeze/src/Breeze.Wallet/Temp/ConcurrentObservableHashSet.cs
+75
-0
Height.cs
Breeze/src/Breeze.Wallet/Temp/Height.cs
+107
-0
SmartMerkleBlock.cs
Breeze/src/Breeze.Wallet/Temp/SmartMerkleBlock.cs
+125
-0
SmartTransaction.cs
Breeze/src/Breeze.Wallet/Temp/SmartTransaction.cs
+128
-0
Tracker.cs
Breeze/src/Breeze.Wallet/Temp/Tracker.cs
+369
-0
UnprocessedBlockBuffer.cs
Breeze/src/Breeze.Wallet/Temp/UnprocessedBlockBuffer.cs
+56
-0
Util.cs
Breeze/src/Breeze.Wallet/Temp/Util.cs
+55
-0
No files found.
Breeze/src/Breeze.Wallet/Breeze.Wallet.csproj
View file @
73763b96
...
...
@@ -16,6 +16,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConcurrentHashSet" Version="1.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" />
<PackageReference Include="Stratis.Bitcoin" Version="1.0.1.5-alpha" />
</ItemGroup>
...
...
Breeze/src/Breeze.Wallet/Temp/ConcurrentObservableDictionary.cs
0 → 100644
View file @
73763b96
//from https://github.com/brianchance/MonoTouchMVVMCrossValidationTester/blob/master/Validation.Core/ConcurrentObservableDictionary.cs
//modified
using
System
;
using
System.Collections.Concurrent
;
using
System.Linq
;
using
System.ComponentModel
;
using
System.Collections.Generic
;
using
System.Collections.Specialized
;
namespace
System.Collections.ObjectModel
{
public
class
ConcurrentObservableDictionary
<
TKey
,
TValue
>
:
IDictionary
<
TKey
,
TValue
>,
INotifyCollectionChanged
,
INotifyPropertyChanged
{
private
const
string
CountString
=
"Count"
;
private
const
string
IndexerName
=
"Item[]"
;
private
const
string
KeysName
=
"Keys"
;
private
const
string
ValuesName
=
"Values"
;
private
readonly
object
Lock
=
new
object
();
protected
ConcurrentDictionary
<
TKey
,
TValue
>
ConcurrentDictionary
{
get
;
private
set
;
}
#
region
Constructors
public
ConcurrentObservableDictionary
()
{
ConcurrentDictionary
=
new
ConcurrentDictionary
<
TKey
,
TValue
>();
}
public
ConcurrentObservableDictionary
(
ConcurrentDictionary
<
TKey
,
TValue
>
dictionary
)
{
ConcurrentDictionary
=
new
ConcurrentDictionary
<
TKey
,
TValue
>(
dictionary
);
}
public
ConcurrentObservableDictionary
(
IEqualityComparer
<
TKey
>
comparer
)
{
ConcurrentDictionary
=
new
ConcurrentDictionary
<
TKey
,
TValue
>(
comparer
);
}
public
ConcurrentObservableDictionary
(
IDictionary
<
TKey
,
TValue
>
dictionary
,
IEqualityComparer
<
TKey
>
comparer
)
{
ConcurrentDictionary
=
new
ConcurrentDictionary
<
TKey
,
TValue
>(
dictionary
,
comparer
);
}
#
endregion
#
region
IDictionary
<
TKey
,
TValue
>
Members
public
void
Add
(
TKey
key
,
TValue
value
)
=>
Insert
(
key
,
value
,
true
);
public
bool
ContainsKey
(
TKey
key
)
=>
ConcurrentDictionary
.
ContainsKey
(
key
);
public
ICollection
<
TKey
>
Keys
=>
ConcurrentDictionary
.
Keys
;
public
bool
Remove
(
TKey
key
)
=>
Remove
(
key
,
suppressNotifications
:
false
);
private
bool
Remove
(
TKey
key
,
bool
suppressNotifications
)
{
lock
(
Lock
)
{
TValue
value
;
var
ret
=
ConcurrentDictionary
.
TryRemove
(
key
,
out
value
);
if
(
ret
&&
!
suppressNotifications
)
OnCollectionChanged
();
return
ret
;
}
}
public
bool
TryGetValue
(
TKey
key
,
out
TValue
value
)
=>
ConcurrentDictionary
.
TryGetValue
(
key
,
out
value
);
public
ICollection
<
TValue
>
Values
=>
ConcurrentDictionary
.
Values
;
public
TValue
this
[
TKey
key
]
{
get
{
TValue
value
;
return
TryGetValue
(
key
,
out
value
)
?
value
:
default
(
TValue
);
}
set
{
Insert
(
key
,
value
,
false
);
}
}
#
endregion
#
region
ICollection
<
KeyValuePair
<
TKey
,
TValue
>>
Members
public
void
Add
(
KeyValuePair
<
TKey
,
TValue
>
item
)
=>
Insert
(
item
.
Key
,
item
.
Value
,
true
);
public
void
Clear
()
{
lock
(
Lock
)
{
if
(
ConcurrentDictionary
.
Count
>
0
)
{
ConcurrentDictionary
.
Clear
();
OnCollectionChanged
();
}
}
}
public
bool
Contains
(
KeyValuePair
<
TKey
,
TValue
>
item
)
=>
ConcurrentDictionary
.
Contains
(
item
);
/// <summary>
/// NotImplementedException
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public
void
CopyTo
(
KeyValuePair
<
TKey
,
TValue
>[]
array
,
int
arrayIndex
)
{
throw
new
NotImplementedException
();
}
/// <summary>
/// NotImplementedException
/// </summary>
public
bool
IsReadOnly
{
get
{
throw
new
NotImplementedException
();
}
}
public
int
Count
=>
ConcurrentDictionary
.
Count
;
public
bool
Remove
(
KeyValuePair
<
TKey
,
TValue
>
item
)
=>
Remove
(
item
.
Key
);
#
endregion
#
region
IEnumerable
<
KeyValuePair
<
TKey
,
TValue
>>
Members
public
IEnumerator
<
KeyValuePair
<
TKey
,
TValue
>>
GetEnumerator
()
=>
ConcurrentDictionary
.
GetEnumerator
();
#
endregion
#
region
IEnumerable
Members
IEnumerator
IEnumerable
.
GetEnumerator
()
=>
((
IEnumerable
)
ConcurrentDictionary
).
GetEnumerator
();
#
endregion
#
region
INotifyCollectionChanged
Members
public
event
NotifyCollectionChangedEventHandler
CollectionChanged
;
#
endregion
#
region
INotifyPropertyChanged
Members
public
event
PropertyChangedEventHandler
PropertyChanged
;
#
endregion
public
void
AddOrReplace
(
TKey
key
,
TValue
value
)
{
if
(
ContainsKey
(
key
))
{
Remove
(
key
,
suppressNotifications
:
true
);
Add
(
key
,
value
);
}
else
{
Add
(
key
,
value
);
}
}
/// <summary>
/// NotImplementedException
/// </summary>
/// <param name="items"></param>
public
void
AddRange
(
IDictionary
<
TKey
,
TValue
>
items
)
{
throw
new
NotImplementedException
();
}
private
void
Insert
(
TKey
key
,
TValue
value
,
bool
add
)
{
lock
(
Lock
)
{
if
(
key
==
null
)
throw
new
ArgumentNullException
(
nameof
(
key
));
TValue
item
;
if
(
ConcurrentDictionary
.
TryGetValue
(
key
,
out
item
))
{
if
(
add
)
throw
new
ArgumentException
(
"An item with the same key has already been added."
);
if
(
Equals
(
item
,
value
))
return
;
ConcurrentDictionary
[
key
]
=
value
;
OnCollectionChanged
(
NotifyCollectionChangedAction
.
Replace
,
new
KeyValuePair
<
TKey
,
TValue
>(
key
,
value
),
new
KeyValuePair
<
TKey
,
TValue
>(
key
,
item
));
OnPropertyChanged
(
key
.
ToString
());
}
else
{
ConcurrentDictionary
[
key
]
=
value
;
OnCollectionChanged
(
NotifyCollectionChangedAction
.
Add
,
new
KeyValuePair
<
TKey
,
TValue
>(
key
,
value
));
OnPropertyChanged
(
key
.
ToString
());
}
}
}
private
void
OnPropertyChanged
()
{
OnPropertyChanged
(
CountString
);
OnPropertyChanged
(
IndexerName
);
OnPropertyChanged
(
KeysName
);
OnPropertyChanged
(
ValuesName
);
}
protected
virtual
void
OnPropertyChanged
(
string
propertyName
)
{
PropertyChanged
?.
Invoke
(
this
,
new
PropertyChangedEventArgs
(
propertyName
));
}
private
void
OnCollectionChanged
()
{
OnPropertyChanged
();
CollectionChanged
?.
Invoke
(
this
,
new
NotifyCollectionChangedEventArgs
(
NotifyCollectionChangedAction
.
Reset
));
}
private
void
OnCollectionChanged
(
NotifyCollectionChangedAction
action
,
KeyValuePair
<
TKey
,
TValue
>
changedItem
)
{
OnPropertyChanged
();
CollectionChanged
?.
Invoke
(
this
,
new
NotifyCollectionChangedEventArgs
(
action
,
changedItem
,
0
));
}
private
void
OnCollectionChanged
(
NotifyCollectionChangedAction
action
,
KeyValuePair
<
TKey
,
TValue
>
newItem
,
KeyValuePair
<
TKey
,
TValue
>
oldItem
)
{
OnPropertyChanged
();
CollectionChanged
?.
Invoke
(
this
,
new
NotifyCollectionChangedEventArgs
(
action
,
newItem
,
oldItem
,
0
));
}
private
void
OnCollectionChanged
(
NotifyCollectionChangedAction
action
,
IList
newItems
)
{
OnPropertyChanged
();
CollectionChanged
?.
Invoke
(
this
,
new
NotifyCollectionChangedEventArgs
(
action
,
newItems
,
0
));
}
}
}
\ No newline at end of file
Breeze/src/Breeze.Wallet/Temp/ConcurrentObservableHashSet.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections
;
using
System.Collections.Concurrent
;
using
System.Linq
;
using
System.ComponentModel
;
using
System.Collections.Generic
;
using
System.Collections.Specialized
;
using
ConcurrentCollections
;
namespace
System.Collections.ObjectModel
{
public
class
ConcurrentObservableHashSet
<
T
>
:
INotifyCollectionChanged
,
IReadOnlyCollection
<
T
>
{
protected
ConcurrentHashSet
<
T
>
ConcurrentHashSet
{
get
;
}
private
readonly
object
Lock
=
new
object
();
public
ConcurrentObservableHashSet
()
{
ConcurrentHashSet
=
new
ConcurrentHashSet
<
T
>();
}
public
event
NotifyCollectionChangedEventHandler
CollectionChanged
;
private
void
OnCollectionChanged
()
{
CollectionChanged
?.
Invoke
(
this
,
new
NotifyCollectionChangedEventArgs
(
NotifyCollectionChangedAction
.
Reset
));
}
IEnumerator
IEnumerable
.
GetEnumerator
()
=>
GetEnumerator
();
public
IEnumerator
<
T
>
GetEnumerator
()
=>
ConcurrentHashSet
.
GetEnumerator
();
public
bool
TryAdd
(
T
item
)
{
lock
(
Lock
)
{
if
(
ConcurrentHashSet
.
Add
(
item
))
{
OnCollectionChanged
();
return
true
;
}
return
false
;
}
}
public
void
Clear
()
{
lock
(
Lock
)
{
if
(
ConcurrentHashSet
.
Count
>
0
)
{
ConcurrentHashSet
.
Clear
();
OnCollectionChanged
();
}
}
}
public
bool
Contains
(
T
item
)
=>
ConcurrentHashSet
.
Contains
(
item
);
public
bool
TryRemove
(
T
item
)
{
lock
(
Lock
)
{
if
(
ConcurrentHashSet
.
TryRemove
(
item
))
{
OnCollectionChanged
();
return
true
;
}
return
false
;
}
}
public
int
Count
=>
ConcurrentHashSet
.
Count
;
}
}
Breeze/src/Breeze.Wallet/Temp/Height.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading.Tasks
;
namespace
HBitcoin.Models
{
public
struct
Height
:
IEquatable
<
Height
>,
IEquatable
<
int
>,
IComparable
<
Height
>,
IComparable
<
int
>
{
public
HeightType
Type
{
get
;
}
private
readonly
int
_value
;
public
int
Value
{
get
{
if
(
Type
==
HeightType
.
Chain
)
return
_value
;
if
(
Type
==
HeightType
.
MemPool
)
return
int
.
MaxValue
-
1
;
//if(Type == HeightType.Unknown)
return
int
.
MaxValue
;
}
}
public
static
Height
MemPool
=>
new
Height
(
HeightType
.
MemPool
);
public
static
Height
Unknown
=>
new
Height
(
HeightType
.
Unknown
);
public
Height
(
int
height
)
{
if
(
height
<
0
)
throw
new
ArgumentException
(
$"
{
nameof
(
height
)}
:
{
height
}
cannot be < 0"
);
if
(
height
==
int
.
MaxValue
)
Type
=
HeightType
.
Unknown
;
else
if
(
height
==
int
.
MaxValue
-
1
)
Type
=
HeightType
.
MemPool
;
else
Type
=
HeightType
.
Chain
;
_value
=
height
;
}
public
Height
(
string
heightOrHeightType
)
{
var
trimmed
=
heightOrHeightType
.
Trim
();
if
(
trimmed
==
HeightType
.
MemPool
.
ToString
())
this
=
MemPool
;
else
if
(
trimmed
==
HeightType
.
Unknown
.
ToString
())
this
=
Unknown
;
else
this
=
new
Height
(
int
.
Parse
(
trimmed
));
}
public
Height
(
HeightType
type
)
{
if
(
type
==
HeightType
.
Chain
)
throw
new
NotSupportedException
(
$"For
{
type
}
height must be specified"
);
Type
=
type
;
if
(
Type
==
HeightType
.
MemPool
)
_value
=
int
.
MaxValue
-
1
;
else
_value
=
int
.
MaxValue
;
// HeightType.Unknown
}
public
override
string
ToString
()
{
if
(
Type
==
HeightType
.
Chain
)
return
Value
.
ToString
();
else
return
Type
.
ToString
();
}
#
region
EqualityAndComparison
public
override
bool
Equals
(
object
obj
)
=>
obj
is
Height
&&
this
==
(
Height
)
obj
;
public
bool
Equals
(
Height
other
)
=>
this
==
other
;
public
override
int
GetHashCode
()
=>
Value
.
GetHashCode
();
public
static
bool
operator
==(
Height
x
,
Height
y
)
=>
x
.
Value
==
y
.
Value
;
public
static
bool
operator
!=(
Height
x
,
Height
y
)
=>
!(
x
==
y
);
public
bool
Equals
(
int
other
)
=>
Value
==
other
;
public
static
bool
operator
==(
int
x
,
Height
y
)
=>
x
==
y
.
Value
;
public
static
bool
operator
==(
Height
x
,
int
y
)
=>
x
.
Value
==
y
;
public
static
bool
operator
!=(
int
x
,
Height
y
)
=>
!(
x
==
y
);
public
static
bool
operator
!=(
Height
x
,
int
y
)
=>
!(
x
==
y
);
public
int
CompareTo
(
Height
other
)
=>
Value
.
CompareTo
(
other
.
Value
);
public
int
CompareTo
(
int
other
)
{
if
(
Value
>
other
)
return
-
1
;
if
(
Value
==
other
)
return
0
;
return
1
;
}
public
static
bool
operator
>(
Height
x
,
Height
y
)
=>
x
.
Value
>
y
.
Value
;
public
static
bool
operator
<(
Height
x
,
Height
y
)
=>
x
.
Value
<
y
.
Value
;
public
static
bool
operator
>=(
Height
x
,
Height
y
)
=>
x
.
Value
>=
y
.
Value
;
public
static
bool
operator
<=(
Height
x
,
Height
y
)
=>
x
.
Value
<=
y
.
Value
;
public
static
bool
operator
>(
int
x
,
Height
y
)
=>
x
>
y
.
Value
;
public
static
bool
operator
>(
Height
x
,
int
y
)
=>
x
.
Value
>
y
;
public
static
bool
operator
<(
int
x
,
Height
y
)
=>
x
<
y
.
Value
;
public
static
bool
operator
<(
Height
x
,
int
y
)
=>
x
.
Value
<
y
;
public
static
bool
operator
>=(
int
x
,
Height
y
)
=>
x
>=
y
.
Value
;
public
static
bool
operator
<=(
int
x
,
Height
y
)
=>
x
<=
y
.
Value
;
public
static
bool
operator
>=(
Height
x
,
int
y
)
=>
x
.
Value
>=
y
;
public
static
bool
operator
<=(
Height
x
,
int
y
)
=>
x
.
Value
<=
y
;
#
endregion
}
public
enum
HeightType
{
Chain
,
MemPool
,
Unknown
}
}
Breeze/src/Breeze.Wallet/Temp/SmartMerkleBlock.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
ConcurrentCollections
;
using
HBitcoin.Models
;
using
NBitcoin
;
namespace
HBitcoin.Models
{
public
class
SmartMerkleBlock
:
IEquatable
<
SmartMerkleBlock
>,
IComparable
<
SmartMerkleBlock
>
{
#
region
Members
public
Height
Height
{
get
;
}
public
MerkleBlock
MerkleBlock
{
get
;
}
public
IEnumerable
<
uint256
>
GetMatchedTransactions
()
=>
MerkleBlock
.
PartialMerkleTree
.
GetMatchedTransactions
();
public
uint
TransactionCount
=>
MerkleBlock
.
PartialMerkleTree
.
TransactionCount
;
#
endregion
#
region
Constructors
public
SmartMerkleBlock
()
{
}
public
SmartMerkleBlock
(
Height
height
,
Block
block
,
params
uint256
[]
interestedTransactionIds
)
{
Height
=
height
;
MerkleBlock
=
interestedTransactionIds
==
null
||
interestedTransactionIds
.
Length
==
0
?
block
.
Filter
()
:
block
.
Filter
(
interestedTransactionIds
);
}
public
SmartMerkleBlock
(
int
height
,
Block
block
,
params
uint256
[]
interestedTransactionIds
)
{
Height
=
new
Height
(
height
);
MerkleBlock
=
interestedTransactionIds
==
null
||
interestedTransactionIds
.
Length
==
0
?
block
.
Filter
()
:
block
.
Filter
(
interestedTransactionIds
);
}
public
SmartMerkleBlock
(
Height
height
,
MerkleBlock
merkleBlock
)
{
Height
=
height
;
MerkleBlock
=
merkleBlock
;
}
#
endregion
#
region
Formatting
public
static
byte
[]
ToBytes
(
SmartMerkleBlock
smartMerkleBlock
)
=>
BitConverter
.
GetBytes
(
smartMerkleBlock
.
Height
.
Value
)
// 4bytes
.
Concat
(
smartMerkleBlock
.
MerkleBlock
.
ToBytes
())
.
ToArray
();
public
byte
[]
ToBytes
()
=>
ToBytes
(
this
);
public
static
SmartMerkleBlock
FromBytes
(
byte
[]
bytes
)
{
var
heightBytes
=
bytes
.
Take
(
4
).
ToArray
();
var
merkleBlockBytes
=
bytes
.
Skip
(
4
).
ToArray
();
var
height
=
new
Height
(
BitConverter
.
ToInt32
(
heightBytes
,
startIndex
:
0
));
// Bypass NBitcoin bug
var
merkleBlock
=
new
MerkleBlock
();
if
(!
merkleBlock
.
ToBytes
().
SequenceEqual
(
merkleBlockBytes
))
// if not default MerkleBlock
{
merkleBlock
.
FromBytes
(
merkleBlockBytes
);
}
return
new
SmartMerkleBlock
(
height
,
merkleBlock
);
}
#
endregion
#
region
EqualityAndComparison
public
override
bool
Equals
(
object
obj
)
=>
obj
is
SmartMerkleBlock
&&
this
==
(
SmartMerkleBlock
)
obj
;
public
bool
Equals
(
SmartMerkleBlock
other
)
=>
this
==
other
;
public
override
int
GetHashCode
()
{
var
hash
=
Height
.
GetHashCode
();
hash
=
hash
^
MerkleBlock
.
Header
.
GetHash
().
GetHashCode
();
hash
=
hash
^
MerkleBlock
.
Header
.
HashPrevBlock
.
GetHashCode
();
hash
=
hash
^
MerkleBlock
.
Header
.
HashMerkleRoot
.
GetHashCode
();
foreach
(
uint256
txhash
in
GetMatchedTransactions
())
hash
=
hash
^
txhash
.
GetHashCode
();
return
hash
;
}
public
static
bool
operator
==(
SmartMerkleBlock
x
,
SmartMerkleBlock
y
)
{
if
(
x
.
Height
!=
y
.
Height
)
return
false
;
if
(
x
.
MerkleBlock
.
Header
.
GetHash
()
!=
y
.
MerkleBlock
.
Header
.
GetHash
())
return
false
;
if
(
x
.
MerkleBlock
.
Header
.
HashPrevBlock
!=
y
.
MerkleBlock
.
Header
.
HashPrevBlock
)
return
false
;
if
(
x
.
MerkleBlock
.
Header
.
HashMerkleRoot
!=
y
.
MerkleBlock
.
Header
.
HashMerkleRoot
)
return
false
;
if
(
x
.
TransactionCount
!=
y
.
TransactionCount
)
return
false
;
if
(
x
.
TransactionCount
==
0
)
return
true
;
if
(!
x
.
GetMatchedTransactions
().
SequenceEqual
(
y
.
GetMatchedTransactions
()))
return
false
;
return
true
;
}
public
static
bool
operator
!=(
SmartMerkleBlock
x
,
SmartMerkleBlock
y
)
=>
!(
x
==
y
);
public
int
CompareTo
(
SmartMerkleBlock
other
)
=>
Height
.
CompareTo
(
other
.
Height
);
public
static
bool
operator
>(
SmartMerkleBlock
x
,
SmartMerkleBlock
y
)
=>
x
.
Height
>
y
.
Height
;
public
static
bool
operator
<(
SmartMerkleBlock
x
,
SmartMerkleBlock
y
)
=>
x
.
Height
<
y
.
Height
;
public
static
bool
operator
>=(
SmartMerkleBlock
x
,
SmartMerkleBlock
y
)
=>
x
.
Height
>=
y
.
Height
;
public
static
bool
operator
<=(
SmartMerkleBlock
x
,
SmartMerkleBlock
y
)
=>
x
.
Height
<=
y
.
Height
;
#
endregion
}
}
Breeze/src/Breeze.Wallet/Temp/SmartTransaction.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
HBitcoin.Models
;
using
NBitcoin
;
namespace
HBitcoin.Models
{
public
class
SmartTransaction
:
IEquatable
<
SmartTransaction
>
{
#
region
Members
public
Height
Height
{
get
;
}
public
Transaction
Transaction
{
get
;
}
public
bool
Confirmed
=>
Height
.
Type
==
HeightType
.
Chain
;
public
uint256
GetHash
()
=>
Transaction
.
GetHash
();
#
endregion
#
region
Constructors
public
SmartTransaction
()
{
}
public
SmartTransaction
(
Transaction
transaction
,
Height
height
)
{
Height
=
height
;
Transaction
=
transaction
;
}
#
endregion
#
region
Equality
public
bool
Equals
(
SmartTransaction
other
)
=>
GetHash
().
Equals
(
other
.
GetHash
());
public
bool
Equals
(
Transaction
other
)
=>
GetHash
().
Equals
(
other
.
GetHash
());
public
override
bool
Equals
(
object
obj
)
{
bool
rc
=
false
;
if
(
obj
is
SmartTransaction
)
{
var
transaction
=
(
SmartTransaction
)
obj
;
rc
=
GetHash
().
Equals
(
transaction
.
GetHash
());
}
else
if
(
obj
is
Transaction
)
{
var
transaction
=
(
Transaction
)
obj
;
rc
=
GetHash
().
Equals
(
transaction
.
GetHash
());
}
return
rc
;
}
public
override
int
GetHashCode
()
{
return
GetHash
().
GetHashCode
();
}
public
static
bool
operator
!=(
SmartTransaction
tx1
,
SmartTransaction
tx2
)
{
return
!(
tx1
==
tx2
);
}
public
static
bool
operator
==(
SmartTransaction
tx1
,
SmartTransaction
tx2
)
{
bool
rc
;
if
(
ReferenceEquals
(
tx1
,
tx2
))
rc
=
true
;
else
if
((
object
)
tx1
==
null
||
(
object
)
tx2
==
null
)
{
rc
=
false
;
}
else
{
rc
=
tx1
.
GetHash
().
Equals
(
tx2
.
GetHash
());
}
return
rc
;
}
public
static
bool
operator
==(
Transaction
tx1
,
SmartTransaction
tx2
)
{
bool
rc
;
if
((
object
)
tx1
==
null
||
(
object
)
tx2
==
null
)
{
rc
=
false
;
}
else
{
rc
=
tx1
.
GetHash
().
Equals
(
tx2
.
GetHash
());
}
return
rc
;
}
public
static
bool
operator
!=(
Transaction
tx1
,
SmartTransaction
tx2
)
{
return
!(
tx1
==
tx2
);
}
public
static
bool
operator
==(
SmartTransaction
tx1
,
Transaction
tx2
)
{
bool
rc
;
if
((
object
)
tx1
==
null
||
(
object
)
tx2
==
null
)
{
rc
=
false
;
}
else
{
rc
=
tx1
.
GetHash
().
Equals
(
tx2
.
GetHash
());
}
return
rc
;
}
public
static
bool
operator
!=(
SmartTransaction
tx1
,
Transaction
tx2
)
{
return
!(
tx1
==
tx2
);
}
#
endregion
}
}
Breeze/src/Breeze.Wallet/Temp/Tracker.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.ObjectModel
;
using
System.Diagnostics
;
using
System.IO
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
ConcurrentCollections
;
using
HBitcoin.Models
;
using
NBitcoin
;
namespace
HBitcoin.FullBlockSpv
{
public
class
Tracker
{
#
region
Members
public
Network
Network
{
get
;
private
set
;
}
public
ConcurrentHashSet
<
SmartMerkleBlock
>
MerkleChain
{
get
;
}
=
new
ConcurrentHashSet
<
SmartMerkleBlock
>();
/// <summary>
///
/// </summary>
/// <param name="scriptPubKey"></param>
/// <param name="receivedTransactions">int: block height</param>
/// <param name="spentTransactions">int: block height</param>
/// <returns></returns>
public
bool
TryFindConfirmedTransactions
(
Script
scriptPubKey
,
out
ConcurrentHashSet
<
SmartTransaction
>
receivedTransactions
,
out
ConcurrentHashSet
<
SmartTransaction
>
spentTransactions
)
{
var
found
=
false
;
receivedTransactions
=
new
ConcurrentHashSet
<
SmartTransaction
>();
spentTransactions
=
new
ConcurrentHashSet
<
SmartTransaction
>();
foreach
(
var
tx
in
TrackedTransactions
.
Where
(
x
=>
x
.
Confirmed
))
{
// if already has that tx continue
if
(
receivedTransactions
.
Any
(
x
=>
x
.
GetHash
()
==
tx
.
GetHash
()))
continue
;
foreach
(
var
output
in
tx
.
Transaction
.
Outputs
)
{
if
(
output
.
ScriptPubKey
.
Equals
(
scriptPubKey
))
{
receivedTransactions
.
Add
(
tx
);
found
=
true
;
}
}
}
if
(
found
)
{
foreach
(
var
tx
in
TrackedTransactions
.
Where
(
x
=>
x
.
Confirmed
))
{
// if already has that tx continue
if
(
spentTransactions
.
Any
(
x
=>
x
.
GetHash
()
==
tx
.
GetHash
()))
continue
;
foreach
(
var
input
in
tx
.
Transaction
.
Inputs
)
{
if
(
receivedTransactions
.
Select
(
x
=>
x
.
GetHash
()).
Contains
(
input
.
PrevOut
.
Hash
))
{
spentTransactions
.
Add
(
tx
);
found
=
true
;
}
}
}
}
return
found
;
}
/// <summary>
///
/// </summary>
/// <param name="scriptPubKey"></param>
/// <returns>if never had any money on it</returns>
public
bool
IsClean
(
Script
scriptPubKey
)
=>
TrackedTransactions
.
All
(
tx
=>
!
tx
.
Transaction
.
Outputs
.
Any
(
output
=>
output
.
ScriptPubKey
.
Equals
(
scriptPubKey
)));
public
ConcurrentObservableHashSet
<
SmartTransaction
>
TrackedTransactions
{
get
;
}
=
new
ConcurrentObservableHashSet
<
SmartTransaction
>();
public
ConcurrentHashSet
<
Script
>
TrackedScriptPubKeys
{
get
;
}
=
new
ConcurrentHashSet
<
Script
>();
public
readonly
UnprocessedBlockBuffer
UnprocessedBlockBuffer
=
new
UnprocessedBlockBuffer
();
private
Height
_bestHeight
=
Height
.
Unknown
;
public
Height
BestHeight
{
get
{
return
_bestHeight
;
}
private
set
{
if
(
_bestHeight
==
value
)
return
;
_bestHeight
=
value
;
OnBestHeightChanged
();
}
}
public
event
EventHandler
BestHeightChanged
;
private
void
OnBestHeightChanged
()
=>
BestHeightChanged
?.
Invoke
(
this
,
EventArgs
.
Empty
);
public
int
BlockCount
=>
MerkleChain
.
Count
;
#
endregion
#
region
Constructors
private
Tracker
()
{
}
public
Tracker
(
Network
network
)
{
Network
=
network
;
UnprocessedBlockBuffer
.
HaveBlocks
+=
UnprocessedBlockBuffer_HaveBlocks
;
}
#
endregion
#
region
Tracking
private
IEnumerable
<
SmartTransaction
>
GetNotYetFoundTrackedTransactions
()
{
var
notFound
=
new
HashSet
<
SmartTransaction
>();
foreach
(
var
tx
in
TrackedTransactions
.
Where
(
x
=>
!
x
.
Confirmed
))
{
notFound
.
Add
(
tx
);
}
return
notFound
;
}
#
endregion
public
void
ReorgOne
()
{
// remove the last block
if
(
MerkleChain
.
Count
!=
0
)
{
if
(
MerkleChain
.
TryRemove
(
MerkleChain
.
Max
()))
{
BestHeight
=
MerkleChain
.
Max
().
Height
;
}
}
}
public
void
AddOrReplaceBlock
(
Height
height
,
Block
block
)
{
UnprocessedBlockBuffer
.
TryAddOrReplace
(
height
,
block
);
}
#
region
TransactionProcessing
/// <returns>if processed it transaction</returns>
public
bool
ProcessTransaction
(
SmartTransaction
transaction
)
{
// 1. If already tracking can we update it?
var
found
=
TrackedTransactions
.
FirstOrDefault
(
x
=>
x
==
transaction
);
if
(
found
!=
default
(
SmartTransaction
))
{
// if in a lower level don't track
if
(
found
.
Height
.
Type
<=
transaction
.
Height
.
Type
)
return
false
;
else
{
// else update
TrackedTransactions
.
TryRemove
(
transaction
);
TrackedTransactions
.
TryAdd
(
transaction
);
return
true
;
}
}
// 2. If this transaction arrived to any of our scriptpubkey track it!
if
(
transaction
.
Transaction
.
Outputs
.
Any
(
output
=>
TrackedScriptPubKeys
.
Contains
(
output
.
ScriptPubKey
)))
{
TrackedTransactions
.
TryAdd
(
transaction
);
return
true
;
}
// 3. If this transaction spends any of our scriptpubkeys track it!
if
(
transaction
.
Transaction
.
Inputs
.
Any
(
input
=>
TrackedTransactions
.
Where
(
ttx
=>
ttx
.
GetHash
()
==
input
.
PrevOut
.
Hash
)
.
Any
(
ttx
=>
TrackedScriptPubKeys
.
Contains
(
ttx
.
Transaction
.
Outputs
[
input
.
PrevOut
.
N
].
ScriptPubKey
))))
{
TrackedTransactions
.
TryAdd
(
transaction
);
return
true
;
}
// if got so far we are not interested
return
false
;
}
/// <returns>transactions it processed, empty if not processed any</returns>
private
HashSet
<
SmartTransaction
>
ProcessTransactions
(
IEnumerable
<
Transaction
>
transactions
,
Height
height
)
{
var
processedTransactions
=
new
HashSet
<
SmartTransaction
>();
try
{
// Process all transactions
foreach
(
var
tx
in
transactions
)
{
var
smartTx
=
new
SmartTransaction
(
tx
,
height
);
if
(
ProcessTransaction
(
smartTx
))
{
processedTransactions
.
Add
(
smartTx
);
}
}
// If processed any then do it again recursively until zero new is processed
if
(
processedTransactions
.
Count
>
0
)
{
var
newlyProcessedTransactions
=
ProcessTransactions
(
transactions
,
height
);
foreach
(
var
ptx
in
newlyProcessedTransactions
)
{
processedTransactions
.
Add
(
ptx
);
}
}
}
catch
(
Exception
ex
)
{
Debug
.
WriteLine
(
$"Ignoring
{
nameof
(
ProcessBlock
)}
exception at height
{
height
}
:"
);
Debug
.
WriteLine
(
ex
);
}
return
processedTransactions
;
}
/// <returns>transactions it processed, empty if not processed any</returns>
private
HashSet
<
SmartTransaction
>
ProcessBlock
(
Height
height
,
Block
block
)
{
var
foundTransactions
=
ProcessTransactions
(
block
.
Transactions
,
height
);
var
smartMerkleBlock
=
new
SmartMerkleBlock
(
height
,
block
,
foundTransactions
.
Select
(
x
=>
x
.
GetHash
()).
ToArray
());
var
sameHeights
=
MerkleChain
.
Where
(
x
=>
x
.
Height
==
height
);
foreach
(
var
elem
in
sameHeights
)
{
MerkleChain
.
TryRemove
(
elem
);
}
MerkleChain
.
Add
(
smartMerkleBlock
);
BestHeight
=
height
;
return
foundTransactions
;
}
#
endregion
private
void
UnprocessedBlockBuffer_HaveBlocks
(
object
sender
,
EventArgs
e
)
{
Height
height
;
Block
block
;
while
(
UnprocessedBlockBuffer
.
TryGetAndRemoveOldest
(
out
height
,
out
block
))
{
ProcessBlock
(
height
,
block
);
}
}
#
region
Saving
private
readonly
SemaphoreSlim
Saving
=
new
SemaphoreSlim
(
1
,
1
);
private
const
string
TrackedScriptPubKeysFileName
=
"TrackedScriptPubKeys.dat"
;
private
const
string
TrackedTransactionsFileName
=
"TrackedTransactions.dat"
;
private
const
string
MerkleChainFileName
=
"MerkleChain.dat"
;
private
static
readonly
byte
[]
blockSep
=
new
byte
[]
{
0x10
,
0x1A
,
0x7B
,
0x23
,
0x5D
,
0x12
,
0x7D
};
public
async
Task
SaveAsync
(
string
trackerFolderPath
)
{
await
Saving
.
WaitAsync
().
ConfigureAwait
(
false
);
try
{
if
(
TrackedScriptPubKeys
.
Count
>
0
||
TrackedTransactions
.
Count
>
0
||
MerkleChain
.
Count
>
0
)
{
Directory
.
CreateDirectory
(
trackerFolderPath
);
}
if
(
TrackedScriptPubKeys
.
Count
>
0
)
{
File
.
WriteAllLines
(
Path
.
Combine
(
trackerFolderPath
,
TrackedScriptPubKeysFileName
),
TrackedScriptPubKeys
.
Select
(
x
=>
x
.
ToString
()));
}
if
(
TrackedTransactions
.
Count
>
0
)
{
File
.
WriteAllLines
(
Path
.
Combine
(
trackerFolderPath
,
TrackedTransactionsFileName
),
TrackedTransactions
.
Select
(
x
=>
$"
{
x
.
Transaction
.
ToHex
()}
:
{
x
.
Height
}
"
));
}
if
(
MerkleChain
.
Count
>
0
)
{
var
path
=
Path
.
Combine
(
trackerFolderPath
,
MerkleChainFileName
);
if
(
File
.
Exists
(
path
))
{
const
string
backupName
=
MerkleChainFileName
+
"_backup"
;
var
backupPath
=
Path
.
Combine
(
trackerFolderPath
,
backupName
);
File
.
Copy
(
path
,
backupPath
,
overwrite
:
true
);
File
.
Delete
(
path
);
}
using
(
FileStream
stream
=
File
.
OpenWrite
(
path
))
{
var
toFile
=
MerkleChain
.
First
().
ToBytes
();
await
stream
.
WriteAsync
(
toFile
,
0
,
toFile
.
Length
).
ConfigureAwait
(
false
);
foreach
(
var
block
in
MerkleChain
.
Skip
(
1
))
{
await
stream
.
WriteAsync
(
blockSep
,
0
,
blockSep
.
Length
).
ConfigureAwait
(
false
);
var
blockBytes
=
block
.
ToBytes
();
await
stream
.
WriteAsync
(
blockBytes
,
0
,
blockBytes
.
Length
).
ConfigureAwait
(
false
);
}
}
}
}
finally
{
Saving
.
Release
();
}
}
public
async
Task
LoadAsync
(
string
trackerFolderPath
)
{
await
Saving
.
WaitAsync
().
ConfigureAwait
(
false
);
try
{
if
(!
Directory
.
Exists
(
trackerFolderPath
))
throw
new
DirectoryNotFoundException
(
$"No Blockchain found at
{
trackerFolderPath
}
"
);
var
tspb
=
Path
.
Combine
(
trackerFolderPath
,
TrackedScriptPubKeysFileName
);
if
(
File
.
Exists
(
tspb
)
&&
new
FileInfo
(
tspb
).
Length
!=
0
)
{
foreach
(
var
line
in
File
.
ReadAllLines
(
tspb
))
{
TrackedScriptPubKeys
.
Add
(
new
Script
(
line
));
}
}
var
tt
=
Path
.
Combine
(
trackerFolderPath
,
TrackedTransactionsFileName
);
if
(
File
.
Exists
(
tt
)
&&
new
FileInfo
(
tt
).
Length
!=
0
)
{
foreach
(
var
line
in
File
.
ReadAllLines
(
tt
))
{
var
pieces
=
line
.
Split
(
':'
);
ProcessTransaction
(
new
SmartTransaction
(
new
Transaction
(
pieces
[
0
]),
new
Height
(
pieces
[
1
])));
}
}
var
pbc
=
Path
.
Combine
(
trackerFolderPath
,
MerkleChainFileName
);
if
(
File
.
Exists
(
pbc
)
&&
new
FileInfo
(
pbc
).
Length
!=
0
)
{
foreach
(
var
block
in
Util
.
Separate
(
File
.
ReadAllBytes
(
pbc
),
blockSep
))
{
SmartMerkleBlock
smartMerkleBlock
=
SmartMerkleBlock
.
FromBytes
(
block
);
MerkleChain
.
Add
(
smartMerkleBlock
);
}
BestHeight
=
MerkleChain
.
Max
().
Height
;
}
}
finally
{
Saving
.
Release
();
}
}
#
endregion
}
}
Breeze/src/Breeze.Wallet/Temp/UnprocessedBlockBuffer.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.ObjectModel
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
HBitcoin.Models
;
using
NBitcoin
;
namespace
HBitcoin.FullBlockSpv
{
public
class
UnprocessedBlockBuffer
{
public
const
int
Capacity
=
50
;
private
readonly
ConcurrentObservableDictionary
<
Height
,
Block
>
_blocks
=
new
ConcurrentObservableDictionary
<
Height
,
Block
>();
public
event
EventHandler
HaveBlocks
;
private
void
OnHaveBlocks
()
=>
HaveBlocks
?.
Invoke
(
this
,
EventArgs
.
Empty
);
/// <summary>
///
/// </summary>
/// <param name="height"></param>
/// <param name="block"></param>
/// <returns>false if we have more than UnprocessedBlockBuffer.Capacity blocks in memory already</returns>
public
bool
TryAddOrReplace
(
Height
height
,
Block
block
)
{
if
(
_blocks
.
Count
>
Capacity
)
return
false
;
_blocks
.
AddOrReplace
(
height
,
block
);
if
(
_blocks
.
Count
==
1
)
OnHaveBlocks
();
return
true
;
}
public
bool
Full
=>
_blocks
.
Count
==
Capacity
;
public
Height
BestHeight
=>
_blocks
.
Count
==
0
?
Height
.
Unknown
:
_blocks
.
Keys
.
Max
();
/// <summary>
///
/// </summary>
/// <returns>false if empty</returns>
public
bool
TryGetAndRemoveOldest
(
out
Height
height
,
out
Block
block
)
{
height
=
Height
.
Unknown
;
block
=
default
(
Block
);
if
(
_blocks
.
Count
==
0
)
return
false
;
height
=
_blocks
.
Keys
.
Min
();
block
=
_blocks
[
height
];
_blocks
.
Remove
(
height
);
return
true
;
}
}
}
Breeze/src/Breeze.Wallet/Temp/Util.cs
0 → 100644
View file @
73763b96
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading.Tasks
;
namespace
HBitcoin
{
internal
static
class
Util
{
internal
static
byte
[][]
Separate
(
byte
[]
source
,
byte
[]
separator
)
{
var
Parts
=
new
List
<
byte
[
]>
();
var
Index
=
0
;
byte
[]
Part
;
for
(
var
I
=
0
;
I
<
source
.
Length
;
++
I
)
{
if
(
Equals
(
source
,
separator
,
I
))
{
Part
=
new
byte
[
I
-
Index
];
Array
.
Copy
(
source
,
Index
,
Part
,
0
,
Part
.
Length
);
Parts
.
Add
(
Part
);
Index
=
I
+
separator
.
Length
;
I
+=
separator
.
Length
-
1
;
}
}
Part
=
new
byte
[
source
.
Length
-
Index
];
Array
.
Copy
(
source
,
Index
,
Part
,
0
,
Part
.
Length
);
Parts
.
Add
(
Part
);
return
Parts
.
ToArray
();
}
private
static
bool
Equals
(
byte
[]
source
,
byte
[]
separator
,
int
index
)
{
for
(
int
i
=
0
;
i
<
separator
.
Length
;
++
i
)
if
(
index
+
i
>=
source
.
Length
||
source
[
index
+
i
]
!=
separator
[
i
])
return
false
;
return
true
;
}
/// <summary>
/// Splits an array into several smaller arrays.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
/// <param name="array">The array to split.</param>
/// <param name="size">The size of the smaller arrays.</param>
/// <returns>An array containing smaller arrays.</returns>
public
static
IEnumerable
<
IEnumerable
<
T
>>
Split
<
T
>(
T
[]
array
,
int
size
)
{
for
(
var
i
=
0
;
i
<
(
float
)
array
.
Length
/
size
;
i
++)
{
yield
return
array
.
Skip
(
i
*
size
).
Take
(
size
);
}
}
}
}
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