@@ -831,6 +831,104 @@ func TestHandleChainUpdate(t *testing.T) {
831831 require .NoError (t , err )
832832}
833833
834+ // matchGetAddressByScript returns a matcher asserting a GetAddress query
835+ // targets the given wallet and script.
836+ func matchGetAddressByScript (walletID uint32 , pkScript []byte ) any {
837+ return mock .MatchedBy (func (query db.GetAddressQuery ) bool {
838+ return query .WalletID == walletID &&
839+ bytes .Equal (query .ScriptPubKey , pkScript )
840+ })
841+ }
842+
843+ // matchRelevantTxParams reports whether the single batched transaction carries
844+ // the expected wallet, hash, receive time, credit address, and published
845+ // status. Block confirmation is validated separately by the caller.
846+ func matchRelevantTxParams (txParams db.CreateTxParams , walletID uint32 ,
847+ tx * wire.MsgTx , addr btcutil.Address , received time.Time ) bool {
848+
849+ creditAddr , ok := txParams .Credits [0 ]
850+ if ! ok || creditAddr == nil || txParams .Tx == nil {
851+ return false
852+ }
853+
854+ return txParams .WalletID == walletID &&
855+ txParams .Tx .TxHash () == tx .TxHash () &&
856+ txParams .Received .Equal (received ) &&
857+ txParams .Status == db .TxStatusPublished &&
858+ creditAddr .EncodeAddress () == addr .EncodeAddress ()
859+ }
860+
861+ // matchUnminedTxBatch returns a matcher asserting an unmined relevant
862+ // transaction is written as a single store batch with the expected credit and
863+ // no confirming block.
864+ func matchUnminedTxBatch (walletID uint32 , tx * wire.MsgTx ,
865+ addr btcutil.Address , received time.Time ) any {
866+
867+ return mock .MatchedBy (func (params db.TxBatchParams ) bool {
868+ if params .WalletID != walletID ||
869+ len (params .Transactions ) != 1 {
870+
871+ return false
872+ }
873+
874+ txParams := params .Transactions [0 ]
875+ if txParams .Block != nil {
876+ return false
877+ }
878+
879+ return matchRelevantTxParams (
880+ txParams , walletID , tx , addr , received ,
881+ )
882+ })
883+ }
884+
885+ // TestProcessRelevantTxUsesStore verifies that relevant transaction
886+ // notifications are routed through the store when store wiring is available.
887+ func TestProcessRelevantTxUsesStore (t * testing.T ) {
888+ t .Parallel ()
889+
890+ // Arrange: Create a syncer with store wiring and a transaction paying to a
891+ // wallet-owned address.
892+ const walletID uint32 = 7
893+
894+ store := & walletmock.Store {}
895+ publisher := & mockTxPublisher {}
896+ s := newSyncer (
897+ Config {ChainParams : & chainParams }, nil , nil , publisher ,
898+ syncerStoreConfig {store : store , walletID : walletID },
899+ )
900+
901+ addr , err := btcutil .NewAddressPubKeyHash (
902+ make ([]byte , 20 ), & chainParams ,
903+ )
904+ require .NoError (t , err )
905+
906+ pkScript , err := txscript .PayToAddrScript (addr )
907+ require .NoError (t , err )
908+
909+ tx := wire .NewMsgTx (1 )
910+ tx .AddTxOut (& wire.TxOut {Value : 1000 , PkScript : pkScript })
911+
912+ received := time .Unix (123 , 0 ).UTC ()
913+ rec , err := wtxmgr .NewTxRecordFromMsgTx (tx , received )
914+ require .NoError (t , err )
915+
916+ store .On ("GetAddress" , mock .Anything ,
917+ matchGetAddressByScript (walletID , pkScript ),
918+ ).Return (& db.AddressInfo {ScriptPubKey : pkScript }, nil ).Once ()
919+
920+ store .On ("ApplyTxBatch" , mock .Anything ,
921+ matchUnminedTxBatch (walletID , tx , addr , received ),
922+ ).Return (nil ).Once ()
923+
924+ // Act: Process an unconfirmed relevant transaction notification.
925+ err = s .processChainUpdate (t .Context (), chain.RelevantTx {TxRecord : rec })
926+
927+ // Assert: The notification was written through the store batch API.
928+ require .NoError (t , err )
929+ store .AssertExpectations (t )
930+ }
931+
834932// TestExtractAddrEntries verifies address extraction from outputs.
835933func TestExtractAddrEntries (t * testing.T ) {
836934 t .Parallel ()
0 commit comments