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
99adb77d
Commit
99adb77d
authored
May 25, 2017
by
Dan Gershony
Committed by
GitHub
May 25, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #80 from bokobza/master
Merkle proofs
parents
662503f8
8b02cbba
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
82 additions
and
32 deletions
+82
-32
IWalletManager.cs
Breeze/src/Breeze.Wallet/IWalletManager.cs
+4
-4
Wallet.cs
Breeze/src/Breeze.Wallet/Wallet.cs
+37
-11
WalletManager.cs
Breeze/src/Breeze.Wallet/WalletManager.cs
+41
-17
No files found.
Breeze/src/Breeze.Wallet/IWalletManager.cs
View file @
99adb77d
...
...
@@ -141,7 +141,7 @@ namespace Breeze.Wallet
/// <param name="allowUnconfirmed">Whether or not we allow this transaction to rely on unconfirmed outputs.</param>
/// <returns></returns>
(
string
hex
,
uint256
transactionId
,
Money
fee
)
BuildTransaction
(
string
walletName
,
string
accountName
,
CoinType
coinType
,
string
password
,
string
destinationAddress
,
Money
amount
,
string
feeType
,
bool
allowUnconfirmed
);
/// <summary>
/// Sends a transaction to the network.
/// </summary>
...
...
@@ -161,8 +161,8 @@ namespace Breeze.Wallet
/// </summary>
/// <param name="transaction">The transaction.</param>
/// <param name="blockHeight">The height of the block this transaction came from. Null if it was not a transaction included in a block.</param>
/// <param name="block
Time">The block time
.</param>
void
ProcessTransaction
(
Transaction
transaction
,
int
?
blockHeight
=
null
,
uint
?
blockTime
=
null
);
/// <param name="block
">The block in which this transaction was included
.</param>
void
ProcessTransaction
(
Transaction
transaction
,
int
?
blockHeight
=
null
,
Block
block
=
null
);
/// <summary>
/// Saves the wallet into the file system.
...
...
@@ -188,4 +188,4 @@ namespace Breeze.Wallet
/// <param name="height">The height of the last block synced.</param>
void
UpdateLastBlockSyncedHeight
(
int
height
);
}
}
}
\ No newline at end of file
Breeze/src/Breeze.Wallet/Wallet.cs
View file @
99adb77d
...
...
@@ -31,7 +31,7 @@ namespace Breeze.Wallet
[
JsonProperty
(
PropertyName
=
"chainCode"
)]
[
JsonConverter
(
typeof
(
ByteArrayConverter
))]
public
byte
[]
ChainCode
{
get
;
set
;
}
/// <summary>
/// The network this wallet is for.
/// </summary>
...
...
@@ -77,7 +77,7 @@ namespace Breeze.Wallet
{
List
<
TransactionData
>
result
=
new
List
<
TransactionData
>();
var
accounts
=
this
.
GetAccountsByCoinType
(
coinType
).
ToList
();
foreach
(
var
address
in
accounts
.
SelectMany
(
a
=>
a
.
ExternalAddresses
).
Concat
(
accounts
.
SelectMany
(
a
=>
a
.
InternalAddresses
)))
{
result
.
AddRange
(
address
.
Transactions
);
...
...
@@ -91,12 +91,12 @@ namespace Breeze.Wallet
/// <param name="coinType">Type of the coin.</param>
/// <returns></returns>
public
IEnumerable
<
Script
>
GetAllPubKeysByCoinType
(
CoinType
coinType
)
{
{
var
accounts
=
this
.
GetAccountsByCoinType
(
coinType
).
ToList
();
foreach
(
var
address
in
accounts
.
SelectMany
(
a
=>
a
.
ExternalAddresses
).
Concat
(
accounts
.
SelectMany
(
a
=>
a
.
InternalAddresses
)))
{
yield
return
address
.
ScriptPubKey
;
}
}
}
}
...
...
@@ -116,7 +116,7 @@ namespace Breeze.Wallet
/// </summary>
[
JsonProperty
(
PropertyName
=
"lastBlockSyncedHeight"
,
NullValueHandling
=
NullValueHandling
.
Ignore
)]
public
int
?
LastBlockSyncedHeight
{
get
;
set
;
}
/// <summary>
/// The accounts used in the wallet.
/// </summary>
...
...
@@ -155,7 +155,7 @@ namespace Breeze.Wallet
throw
new
Exception
(
$"No account with name
{
accountName
}
could be found."
);
}
return
account
;
}
}
}
/// <summary>
...
...
@@ -315,7 +315,7 @@ namespace Breeze.Wallet
/// <returns></returns>
public
IEnumerable
<
TransactionData
>
GetSpendableTransactions
()
{
var
addresses
=
this
.
ExternalAddresses
.
Concat
(
this
.
InternalAddresses
);
var
addresses
=
this
.
ExternalAddresses
.
Concat
(
this
.
InternalAddresses
);
return
addresses
.
SelectMany
(
a
=>
a
.
Transactions
.
Where
(
t
=>
t
.
SpentInTransaction
==
null
&&
t
.
Amount
>
Money
.
Zero
));
}
...
...
@@ -344,7 +344,7 @@ namespace Breeze.Wallet
/// </summary>
[
JsonProperty
(
PropertyName
=
"index"
)]
public
int
Index
{
get
;
set
;
}
/// <summary>
/// The script pub key for this address.
/// </summary>
...
...
@@ -355,7 +355,7 @@ namespace Breeze.Wallet
/// <summary>
/// The Base58 representation of this address.
/// </summary>
[
JsonProperty
(
PropertyName
=
"address"
)]
[
JsonProperty
(
PropertyName
=
"address"
)]
public
string
Address
{
get
;
set
;
}
/// <summary>
...
...
@@ -383,7 +383,7 @@ namespace Breeze.Wallet
/// <c>true</c> if it is a change address; otherwise, <c>false</c>.
/// </returns>
public
bool
IsChangeAddress
()
{
{
return
int
.
Parse
(
this
.
HdPath
.
Split
(
'/'
)[
4
])
==
1
;
}
}
...
...
@@ -431,7 +431,7 @@ namespace Breeze.Wallet
/// </summary>
[
JsonProperty
(
PropertyName
=
"blockHeight"
,
NullValueHandling
=
NullValueHandling
.
Ignore
)]
public
int
?
BlockHeight
{
get
;
set
;
}
/// <summary>
/// Gets or sets the creation time.
/// </summary>
...
...
@@ -439,6 +439,13 @@ namespace Breeze.Wallet
[
JsonConverter
(
typeof
(
DateTimeOffsetConverter
))]
public
DateTimeOffset
CreationTime
{
get
;
set
;
}
/// <summary>
/// Gets or sets the Merkle proof for this transaction.
/// </summary>
[
JsonProperty
(
PropertyName
=
"merkleProof"
,
NullValueHandling
=
NullValueHandling
.
Ignore
)]
public
MerkleProof
MerkleProof
{
get
;
set
;
}
/// <summary>
/// Determines whether this transaction is confirmed.
/// </summary>
...
...
@@ -473,4 +480,23 @@ namespace Breeze.Wallet
[
JsonConverter
(
typeof
(
MoneyJsonConverter
))]
public
Money
Amount
{
get
;
set
;
}
}
/// <summary>
/// An object representing a Merkle proof
/// </summary>
public
class
MerkleProof
{
/// <summary>
/// Gets or sets the merkle root.
/// </summary>
[
JsonProperty
(
PropertyName
=
"merkleRoot"
)]
[
JsonConverter
(
typeof
(
UInt256JsonConverter
))]
public
uint256
MerkleRoot
{
get
;
set
;
}
/// <summary>
/// Gets or sets the merkle path.
/// </summary>
[
JsonProperty
(
PropertyName
=
"merklePath"
,
ItemConverterType
=
typeof
(
UInt256JsonConverter
))]
public
ICollection
<
uint256
>
MerklePath
{
get
;
set
;
}
}
}
\ No newline at end of file
Breeze/src/Breeze.Wallet/WalletManager.cs
View file @
99adb77d
...
...
@@ -451,7 +451,7 @@ namespace Breeze.Wallet
foreach
(
Transaction
transaction
in
block
.
Transactions
)
{
this
.
ProcessTransaction
(
transaction
,
height
,
block
.
Header
.
Time
);
this
.
ProcessTransaction
(
transaction
,
height
,
block
);
}
// update the wallets with the last processed block height
...
...
@@ -459,7 +459,7 @@ namespace Breeze.Wallet
}
/// <inheritdoc />
public
void
ProcessTransaction
(
Transaction
transaction
,
int
?
blockHeight
=
null
,
uint
?
blockTime
=
null
)
public
void
ProcessTransaction
(
Transaction
transaction
,
int
?
blockHeight
=
null
,
Block
block
=
null
)
{
Console
.
WriteLine
(
$"transaction notification: tx hash
{
transaction
.
GetHash
()}
, coin type:
{
this
.
coinType
}
"
);
...
...
@@ -470,7 +470,7 @@ namespace Breeze.Wallet
var
utxo
=
transaction
.
Outputs
.
SingleOrDefault
(
o
=>
pubKey
==
o
.
ScriptPubKey
);
if
(
utxo
!=
null
)
{
AddTransactionToWallet
(
transaction
.
GetHash
(),
transaction
.
Time
,
transaction
.
Outputs
.
IndexOf
(
utxo
),
utxo
.
Value
,
pubKey
,
blockHeight
,
block
Time
);
AddTransactionToWallet
(
transaction
.
GetHash
(),
transaction
.
Time
,
transaction
.
Outputs
.
IndexOf
(
utxo
),
utxo
.
Value
,
pubKey
,
blockHeight
,
block
);
}
}
...
...
@@ -486,7 +486,7 @@ namespace Breeze.Wallet
// We first include the keys we don't hold and then we include the keys we do hold but that are for receiving addresses (which would mean the user paid itself).
IEnumerable
<
TxOut
>
paidoutto
=
transaction
.
Outputs
.
Where
(
o
=>
!
this
.
keysLookup
.
Keys
.
Contains
(
o
.
ScriptPubKey
)
||
(
this
.
keysLookup
.
ContainsKey
(
o
.
ScriptPubKey
)
&&
!
this
.
keysLookup
[
o
.
ScriptPubKey
].
IsChangeAddress
()));
AddTransactionToWallet
(
transaction
.
GetHash
(),
transaction
.
Time
,
null
,
-
tTx
.
Amount
,
keyToSpend
,
blockHeight
,
block
Time
,
tTx
.
Id
,
tTx
.
Index
,
paidoutto
);
AddTransactionToWallet
(
transaction
.
GetHash
(),
transaction
.
Time
,
null
,
-
tTx
.
Amount
,
keyToSpend
,
blockHeight
,
block
,
tTx
.
Id
,
tTx
.
Index
,
paidoutto
);
}
}
...
...
@@ -499,14 +499,15 @@ namespace Breeze.Wallet
/// <param name="amount">The amount.</param>
/// <param name="script">The script.</param>
/// <param name="blockHeight">Height of the block.</param>
/// <param name="block
Time">The block time
.</param>
/// <param name="block
">The block containing the transaction to add
.</param>
/// <param name="spendingTransactionId">The id of the transaction containing the output being spent, if this is a spending transaction.</param>
/// <param name="spendingTransactionIndex">The index of the output in the transaction being referenced, if this is a spending transaction.</param>
private
void
AddTransactionToWallet
(
uint256
transactionHash
,
uint
time
,
int
?
index
,
Money
amount
,
Script
script
,
int
?
blockHeight
=
null
,
uint
?
blockTime
=
null
,
uint256
spendingTransactionId
=
null
,
int
?
spendingTransactionIndex
=
null
,
IEnumerable
<
TxOut
>
paidToOutputs
=
null
)
private
void
AddTransactionToWallet
(
uint256
transactionHash
,
uint
time
,
int
?
index
,
Money
amount
,
Script
script
,
int
?
blockHeight
=
null
,
Block
block
=
null
,
uint256
spendingTransactionId
=
null
,
int
?
spendingTransactionIndex
=
null
,
IEnumerable
<
TxOut
>
paidToOutputs
=
null
)
{
// get the collection of transactions to add to.
this
.
keysLookup
.
TryGetValue
(
script
,
out
HdAddress
address
);
var
isSpendingTransaction
=
paidToOutputs
!=
null
&&
paidToOutputs
.
Any
();
var
trans
=
address
.
Transactions
;
// if it's the first time we see this transaction
...
...
@@ -517,13 +518,18 @@ namespace Breeze.Wallet
Amount
=
amount
,
BlockHeight
=
blockHeight
,
Id
=
transactionHash
,
CreationTime
=
DateTimeOffset
.
FromUnixTimeSeconds
(
blockTime
??
time
),
CreationTime
=
DateTimeOffset
.
FromUnixTimeSeconds
(
block
?.
Header
.
Time
??
time
),
Index
=
index
};
trans
.
Add
(
newTransaction
);
// add the Merkle proof to the (non-spending) transaction
if
(
block
!=
null
&&
!
isSpendingTransaction
)
{
newTransaction
.
MerkleProof
=
this
.
CreateMerkleProof
(
block
,
transactionHash
);
}
// if this is a spending transaction, keep a record of the payments made out to other scripts.
if
(
paidToOutputs
!=
null
&&
paidToOutputs
.
Any
()
)
if
(
isSpendingTransaction
)
{
List
<
PaymentDetails
>
payments
=
new
List
<
PaymentDetails
>();
foreach
(
var
paidToOutput
in
paidToOutputs
)
...
...
@@ -537,17 +543,18 @@ namespace Breeze.Wallet
}
newTransaction
.
Payments
=
payments
;
}
// if this is a spending transaction, mark the spent transaction as such
if
(
spendingTransactionId
!=
null
)
{
// mark the transaction spent by this transaction as such
var
transactions
=
this
.
keysLookup
.
Values
.
SelectMany
(
v
=>
v
.
Transactions
).
Where
(
t
=>
t
.
Id
==
spendingTransactionId
);
if
(
transactions
.
Any
())
{
transactions
.
Single
(
t
=>
t
.
Index
==
spendingTransactionIndex
).
SpentInTransaction
=
transactionHash
;
var
spentTransaction
=
transactions
.
Single
(
t
=>
t
.
Index
==
spendingTransactionIndex
);
spentTransaction
.
SpentInTransaction
=
transactionHash
;
spentTransaction
.
MerkleProof
=
null
;
}
}
trans
.
Add
(
newTransaction
);
}
else
if
(
trans
.
Any
(
t
=>
t
.
Id
==
transactionHash
))
// if this is an unconfirmed transaction now received in a block
{
...
...
@@ -560,9 +567,15 @@ namespace Breeze.Wallet
}
// update the block time
if
(
blockTime
!=
null
)
if
(
block
!=
null
)
{
foundTransaction
.
CreationTime
=
DateTimeOffset
.
FromUnixTimeSeconds
(
block
.
Header
.
Time
);
}
// add the Merkle proof now that the transaction is confirmed in a block
if
(!
isSpendingTransaction
&&
foundTransaction
.
MerkleProof
==
null
)
{
foundTransaction
.
CreationTime
=
DateTimeOffset
.
FromUnixTimeSeconds
(
blockTime
.
Value
);
foundTransaction
.
MerkleProof
=
this
.
CreateMerkleProof
(
block
,
transactionHash
);
}
}
...
...
@@ -570,6 +583,17 @@ namespace Breeze.Wallet
this
.
TransactionFound
?.
Invoke
(
this
,
new
TransactionFoundEventArgs
(
script
,
transactionHash
));
}
private
MerkleProof
CreateMerkleProof
(
Block
block
,
uint256
transactionHash
)
{
MerkleBlock
merkleBlock
=
new
MerkleBlock
(
block
,
new
[]
{
transactionHash
});
return
new
MerkleProof
{
MerkleRoot
=
block
.
Header
.
HashMerkleRoot
,
MerklePath
=
merkleBlock
.
PartialMerkleTree
.
Hashes
};
}
private
void
OnTransactionFound
(
object
sender
,
TransactionFoundEventArgs
a
)
{
foreach
(
Wallet
wallet
in
this
.
Wallets
)
...
...
@@ -835,4 +859,4 @@ namespace Breeze.Wallet
this
.
TransactionHash
=
transactionHash
;
}
}
}
}
\ No newline at end of file
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