18
18
using System . Text . RegularExpressions ;
19
19
using Npgsql ;
20
20
using static NBXplorer . Backend . DbConnectionHelper ;
21
- using Microsoft . AspNetCore . DataProtection . KeyManagement ;
22
21
23
22
24
23
namespace NBXplorer . Backend
@@ -72,7 +71,7 @@ JOIN unnest(@keypaths) AS k(keypath) ON nbxv1_get_keypath_index(d.metadata, k.ke
72
71
code = Network . CryptoCode ,
73
72
wid = w . wid ,
74
73
keypaths = keyPaths . Select ( k => k . ToString ( ) ) . ToArray ( )
75
- } ) ;
74
+ } ) ;
76
75
}
77
76
78
77
public record DescriptorKey ( string code , string descriptor ) ;
@@ -629,19 +628,25 @@ public async Task<TrackedTransaction[]> GetMatches(DbConnectionHelper connection
629
628
}
630
629
async Task < ( TrackedTransaction [ ] TrackedTransactions , SaveTransactionRecord [ ] Saved ) > SaveMatches ( DbConnectionHelper connection , MatchQuery matchQuery , IList < SaveTransactionRecord > records , CancellationToken cancellationToken = default )
631
630
{
632
- HashSet < uint256 > unconfTxs = await connection . GetUnconfirmedTxs ( ) ;
631
+ HashSet < uint256 > unconfTxs = null ; ;
633
632
Dictionary < uint256 , SaveTransactionRecord > txs = new ( ) ;
634
633
HashSet < uint256 > savedTxs = new ( ) ;
635
634
List < dynamic > matchedConflicts = new List < dynamic > ( ) ;
636
635
var scripts = new List < Script > ( ) ;
637
636
foreach ( var record in records )
638
637
{
639
638
txs . TryAdd ( record . Id , record ) ;
640
- if ( record . BlockId is not null && unconfTxs . Contains ( record . Id ) )
641
- // If a block has been found, and we have some unconf transactions
642
- // then we want to add an entry in blks_txs, even if the unconf tx isn't matching
643
- // any wallet. So we add record.
644
- savedTxs . Add ( record . Id ) ;
639
+ if ( record . BlockId is not null )
640
+ {
641
+ unconfTxs ??= await connection . GetUnconfirmedTxs ( ) ;
642
+ if ( unconfTxs . Contains ( record . Id ) )
643
+ {
644
+ // If a block has been found, and we have some unconf transactions
645
+ // then we want to add an entry in blks_txs, even if the unconf tx isn't matching
646
+ // any wallet. So we add record.
647
+ savedTxs . Add ( record . Id ) ;
648
+ }
649
+ }
645
650
}
646
651
SaveTransactionRecord [ ] GetSavedTxs ( ) => txs . Values . Where ( r => savedTxs . Contains ( r . Id ) ) . ToArray ( ) ;
647
652
@@ -681,7 +686,11 @@ public async Task<TrackedTransaction[]> GetMatches(DbConnectionHelper connection
681
686
end :
682
687
if ( savedTxs . Count is 0 )
683
688
return ( Array . Empty < TrackedTransaction > ( ) , GetSavedTxs ( ) ) ;
684
- await connection . SaveTransactions ( savedTxs . Select ( h => txs [ h ] ) . ToArray ( ) ) ;
689
+
690
+ var metadata = await rpc . FetchMempoolInfo ( GetSavedTxs ( ) . Where ( tx => tx . BlockId is null ) . Select ( tx => tx . Id ) , cancellationToken ) ;
691
+ await connection . SaveTransactions ( GetSavedTxs ( ) , metadata ) ;
692
+
693
+
685
694
if ( scripts . Count is 0 )
686
695
return ( Array . Empty < TrackedTransaction > ( ) , GetSavedTxs ( ) ) ;
687
696
var allKeyInfos = await GetKeyInformations ( connection . Connection , scripts ) ;
@@ -727,21 +736,22 @@ private void AddReplacementInfo(List<dynamic> matchedConflicts, TrackedTransacti
727
736
public Task CommitMatches ( DbConnection connection )
728
737
=> connection . ExecuteAsync ( "CALL save_matches(@code)" , new { code = Network . CryptoCode } ) ;
729
738
730
- record SavedTransactionRow ( byte [ ] raw , string blk_id , long ? blk_height , string replaced_by , DateTime seen_at ) ;
731
- public async Task < SavedTransaction [ ] > GetSavedTransactions ( uint256 txid )
739
+ record SavedTransactionRow ( byte [ ] raw , string metadata , string blk_id , long ? blk_height , string replaced_by , DateTime seen_at ) ;
740
+ public async Task < SavedTransaction > GetSavedTransaction ( uint256 txid )
732
741
{
733
742
await using var connection = await connectionFactory . CreateConnectionHelper ( Network ) ;
734
- var tx = await connection . Connection . QueryFirstOrDefaultAsync < SavedTransactionRow > ( "SELECT raw, blk_id, blk_height, replaced_by, seen_at FROM txs WHERE code=@code AND tx_id=@tx_id" , new { code = Network . CryptoCode , tx_id = txid . ToString ( ) } ) ;
743
+ var tx = await connection . Connection . QueryFirstOrDefaultAsync < SavedTransactionRow > ( "SELECT raw, metadata, blk_id, blk_height, replaced_by, seen_at FROM txs WHERE code=@code AND tx_id=@tx_id" , new { code = Network . CryptoCode , tx_id = txid . ToString ( ) } ) ;
735
744
if ( tx ? . raw is null )
736
- return Array . Empty < SavedTransaction > ( ) ;
737
- return new [ ] { new SavedTransaction ( )
745
+ return null ;
746
+ return new SavedTransaction ( )
738
747
{
739
748
BlockHash = tx . blk_id is null ? null : uint256 . Parse ( tx . blk_id ) ,
740
749
BlockHeight = tx . blk_height ,
741
750
Timestamp = new DateTimeOffset ( tx . seen_at ) ,
742
751
Transaction = Transaction . Load ( tx . raw , Network . NBitcoinNetwork ) ,
743
- ReplacedBy = tx . replaced_by is null ? null : uint256 . Parse ( tx . replaced_by )
744
- } } ;
752
+ ReplacedBy = tx . replaced_by is null ? null : uint256 . Parse ( tx . replaced_by ) ,
753
+ Metadata = tx . metadata is null ? null : TransactionMetadata . Parse ( tx . metadata )
754
+ } ;
745
755
}
746
756
public async Task < TrackedTransaction [ ] > GetTransactions ( GetTransactionQuery query , bool includeTransactions = true , CancellationToken cancellation = default )
747
757
{
@@ -794,26 +804,32 @@ async Task<TrackedTransaction[]> GetTransactions(DbConnectionHelper connection,
794
804
}
795
805
}
796
806
797
- var txsToFetch = ( includeTransactions ? trackedById . Keys . Select ( t => t . Item2 ) . AsList ( ) :
798
- // For double spend detection, we need the full transactions from unconfs
799
- trackedById . Where ( t => t . Value . BlockHash is null ) . Select ( t => t . Key . Item2 ) . AsList ( ) ) . ToHashSet ( ) ;
800
- var txRaws = txsToFetch . Count > 0
801
- ? await connection . Connection . QueryAsync < ( string tx_id , byte [ ] raw ) > (
802
- "SELECT t.tx_id, t.raw FROM unnest(@txId) i " +
803
- "JOIN txs t ON t.code=@code AND t.tx_id=i " +
804
- "WHERE t.raw IS NOT NULL;" , new { code = Network . CryptoCode , txId = txsToFetch . ToArray ( ) } )
805
- : Array . Empty < ( string tx_id , byte [ ] raw ) > ( ) ;
806
-
807
- var txRawsById = txRaws . ToDictionary ( t => t . tx_id ) ;
807
+ var txsToFetch = trackedById . Keys . Select ( t => t . Item2 ) . ToHashSet ( ) ;
808
+
809
+ var txMetadata = await connection . Connection . QueryAsync < ( string tx_id , byte [ ] raw , string metadata ) > (
810
+ $ "SELECT t.tx_id, t.raw, t.metadata FROM unnest(@txId) i " +
811
+ "JOIN txs t ON t.code=@code AND t.tx_id=i;" , new { code = Network . CryptoCode , txId = txsToFetch . ToArray ( ) } ) ;
812
+
813
+ var txMetadataByIds = txMetadata . ToDictionary ( t => t . tx_id ) ;
808
814
foreach ( var tracked in trackedById . Values )
809
815
{
810
816
tracked . Sort ( ) ;
811
- if ( ! txRawsById . TryGetValue ( tracked . Key . TxId . ToString ( ) , out var row ) )
817
+ if ( ! txMetadataByIds . TryGetValue ( tracked . Key . TxId . ToString ( ) , out var row ) )
812
818
continue ;
813
- tracked . Transaction = Transaction . Load ( row . raw , Network . NBitcoinNetwork ) ;
814
- tracked . Key = tracked . Key with { IsPruned = false } ;
815
- if ( tracked . BlockHash is null ) // Only need the spend outpoint for double spend detection on unconf txs
816
- tracked . SpentOutpoints . AddInputs ( tracked . Transaction ) ;
819
+ Transaction tx = ( includeTransactions || tracked . BlockHash is null ) && row . raw is not null ? Transaction . Load ( row . raw , Network . NBitcoinNetwork ) : null ;
820
+ if ( tx is not null )
821
+ {
822
+ tracked . Transaction = tx ;
823
+ tracked . Key = tracked . Key with { IsPruned = false } ;
824
+ }
825
+ if ( row . metadata is not null )
826
+ {
827
+ tracked . Metadata = TransactionMetadata . Parse ( row . metadata ) ;
828
+ }
829
+ if ( tracked . BlockHash is null && tx is not null ) // Only need the spend outpoint for double spend detection on unconf txs
830
+ {
831
+ tracked . SpentOutpoints . AddInputs ( tx ) ;
832
+ }
817
833
}
818
834
819
835
if ( Network . IsElement )
@@ -824,7 +840,7 @@ async Task<TrackedTransaction[]> GetTransactions(DbConnectionHelper connection,
824
840
825
841
private async Task UnblindTrackedTransactions ( DbConnectionHelper connection , IEnumerable < TrackedTransaction > trackedTransactions , GetTransactionQuery query )
826
842
{
827
- var keyInfos = ( ( query as GetTransactionQuery . ScriptsTxIds ) ? . KeyInfos ) ? . ToMultiValueDictionary ( k => k . ScriptPubKey ) ;
843
+ var keyInfos = ( ( query as GetTransactionQuery . ScriptsTxIds ) ? . KeyInfos ) ? . ToMultiValueDictionary ( k => k . ScriptPubKey ) ;
828
844
if ( keyInfos is null )
829
845
keyInfos = ( await this . GetKeyInformations ( connection . Connection , trackedTransactions . SelectMany ( t => t . InOuts ) . Select ( s => s . ScriptPubKey ) . ToList ( ) ) ) ;
830
846
foreach ( var tracked in trackedTransactions )
@@ -1065,12 +1081,6 @@ public async Task<TMetadata> GetMetadata<TMetadata>(TrackedSource source, string
1065
1081
return await helper . GetMetadata < TMetadata > ( walletKey . wid , key ) ;
1066
1082
}
1067
1083
1068
- public async Task SaveTransactions ( SaveTransactionRecord [ ] records )
1069
- {
1070
- await using var helper = await connectionFactory . CreateConnectionHelper ( Network ) ;
1071
- await helper . SaveTransactions ( records ) ;
1072
- }
1073
-
1074
1084
public async Task SetIndexProgress ( BlockLocator locator )
1075
1085
{
1076
1086
await using var conn = await connectionFactory . CreateConnection ( ) ;
0 commit comments