@@ -442,13 +442,19 @@ type testBackend struct {
442442 pendingReceipts types.Receipts
443443
444444 // test-only fields for SendRawTransactionSync
445- autoMine bool
446- mined bool
445+ receiptsFeed * event.Feed
446+ headFeed * event.Feed // keep if other tests use it; otherwise remove
447+ autoMine bool
448+
449+ sentTx * types.Transaction
450+ sentTxHash common.Hash
451+
447452 syncDefaultTO time.Duration
448453 syncMaxTO time.Duration
449- sentTx * types.Transaction
450- sentTxHash common.Hash
451- headFeed * event.Feed
454+ }
455+
456+ func fakeBlockHash (txh common.Hash ) common.Hash {
457+ return crypto .Keccak256Hash ([]byte ("testblock" ), txh .Bytes ())
452458}
453459
454460func newTestBackend (t * testing.T , n int , gspec * core.Genesis , engine consensus.Engine , generator func (i int , b * core.BlockGen )) * testBackend {
@@ -476,6 +482,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.E
476482 pending : blocks [n ],
477483 pendingReceipts : receipts [n ],
478484 headFeed : new (event.Feed ),
485+ receiptsFeed : new (event.Feed ),
479486 }
480487 return backend
481488}
@@ -605,23 +612,38 @@ func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) even
605612func (b * testBackend ) SendTx (ctx context.Context , tx * types.Transaction ) error {
606613 b .sentTx = tx
607614 b .sentTxHash = tx .Hash ()
608- if b .autoMine {
609- b .mined = true
615+
616+ if b .autoMine && b .receiptsFeed != nil {
617+ num := b .chain .CurrentHeader ().Number .Uint64 () + 1
618+ bh := fakeBlockHash (tx .Hash ())
619+
620+ r := & types.Receipt {
621+ TxHash : tx .Hash (),
622+ Status : types .ReceiptStatusSuccessful ,
623+ BlockHash : bh ,
624+ BlockNumber : new (big.Int ).SetUint64 (num ),
625+ TransactionIndex : 0 ,
626+ CumulativeGasUsed : 21000 ,
627+ GasUsed : 21000 ,
628+ }
629+ b .receiptsFeed .Send ([]* ReceiptWithTx {{Receipt : r , Tx : tx }})
610630 }
611631 return nil
612632}
613- func (b testBackend ) GetCanonicalTransaction (txHash common.Hash ) (bool , * types.Transaction , common.Hash , uint64 , uint64 ) {
614- // in-memory fast path for tests
615- if b .mined && txHash == b .sentTxHash {
616- return true , b .sentTx , common .HexToHash ("0x01" ), 1 , 0
633+ func (b * testBackend ) GetCanonicalTransaction (txHash common.Hash ) (bool , * types.Transaction , common.Hash , uint64 , uint64 ) {
634+ // Treat the auto-mined tx as canonically placed at head+1.
635+ if b .autoMine && txHash == b .sentTxHash {
636+ num := b .chain .CurrentHeader ().Number .Uint64 () + 1
637+ return true , b .sentTx , fakeBlockHash (txHash ), num , 0
617638 }
618- // fallback to existing DB-backed path
619639 tx , blockHash , blockNumber , index := rawdb .ReadCanonicalTransaction (b .db , txHash )
620640 return tx != nil , tx , blockHash , blockNumber , index
621641}
622- func (b testBackend ) GetCanonicalReceipt (tx * types.Transaction , blockHash common.Hash , blockNumber , blockIndex uint64 ) (* types.Receipt , error ) {
623- // In-memory fast path used by tests
624- if b .mined && tx != nil && tx .Hash () == b .sentTxHash && blockHash == common .HexToHash ("0x01" ) && blockNumber == 1 && blockIndex == 0 {
642+ func (b * testBackend ) GetCanonicalReceipt (tx * types.Transaction , blockHash common.Hash , blockNumber , blockIndex uint64 ) (* types.Receipt , error ) {
643+ if b .autoMine && tx != nil && tx .Hash () == b .sentTxHash &&
644+ blockHash == fakeBlockHash (tx .Hash ()) &&
645+ blockIndex == 0 &&
646+ blockNumber == b .chain .CurrentHeader ().Number .Uint64 ()+ 1 {
625647 return & types.Receipt {
626648 Type : tx .Type (),
627649 Status : types .ReceiptStatusSuccessful ,
@@ -631,9 +653,9 @@ func (b testBackend) GetCanonicalReceipt(tx *types.Transaction, blockHash common
631653 BlockHash : blockHash ,
632654 BlockNumber : new (big.Int ).SetUint64 (blockNumber ),
633655 TransactionIndex : 0 ,
656+ TxHash : tx .Hash (),
634657 }, nil
635658 }
636- // Fallback: use the chain's canonical receipt (DB-backed)
637659 return b .chain .GetCanonicalReceipt (tx , blockHash , blockNumber , blockIndex )
638660}
639661func (b testBackend ) TxIndexDone () bool {
@@ -3961,6 +3983,66 @@ func makeSignedRaw(t *testing.T, api *TransactionAPI, from, to common.Address, v
39613983func makeSelfSignedRaw (t * testing.T , api * TransactionAPI , addr common.Address ) (hexutil.Bytes , * types.Transaction ) {
39623984 return makeSignedRaw (t , api , addr , addr , big .NewInt (0 ))
39633985}
3986+
3987+ func (b * testBackend ) SubscribeTransactionReceipts (txHashes []common.Hash , ch chan <- []* ReceiptWithTx ) event.Subscription {
3988+ // If no feed is wired for this test, return a no-op subscription
3989+ if b .receiptsFeed == nil {
3990+ return event .NewSubscription (func (quit <- chan struct {}) error {
3991+ <- quit
3992+ return nil
3993+ })
3994+ }
3995+
3996+ // No filter => forward batches directly
3997+ if len (txHashes ) == 0 {
3998+ return b .receiptsFeed .Subscribe (ch )
3999+ }
4000+
4001+ // Filtered: wrap the underlying feed and only forward matching receipts
4002+ in := make (chan []* ReceiptWithTx , 1 )
4003+ sub := b .receiptsFeed .Subscribe (in )
4004+
4005+ // Build a hash set for quick filtering
4006+ wanted := make (map [common.Hash ]struct {}, len (txHashes ))
4007+ for _ , h := range txHashes {
4008+ wanted [h ] = struct {}{}
4009+ }
4010+
4011+ return event .NewSubscription (func (quit <- chan struct {}) error {
4012+ defer sub .Unsubscribe ()
4013+ for {
4014+ select {
4015+ case batch , ok := <- in :
4016+ if ! ok {
4017+ return nil
4018+ }
4019+ var out []* ReceiptWithTx
4020+ for _ , r := range batch {
4021+ if r != nil && r .Receipt != nil {
4022+ if _ , ok := wanted [r .Receipt .TxHash ]; ok {
4023+ out = append (out , r )
4024+ }
4025+ }
4026+ }
4027+ if len (out ) == 0 {
4028+ continue
4029+ }
4030+ select {
4031+ case ch <- out :
4032+ case <- quit :
4033+ return nil
4034+ }
4035+ case err , ok := <- sub .Err ():
4036+ if ! ok || err == nil {
4037+ return nil
4038+ }
4039+ return err
4040+ case <- quit :
4041+ return nil
4042+ }
4043+ }
4044+ })
4045+ }
39644046func TestSendRawTransactionSync_Success (t * testing.T ) {
39654047 t .Parallel ()
39664048 genesis := & core.Genesis {
0 commit comments