@@ -3,6 +3,7 @@ package chainaccessor
33import (
44 "context"
55 "fmt"
6+ "math/big"
67 "reflect"
78 "testing"
89
@@ -381,3 +382,231 @@ func TestDefaultAccessor_GetSourceChainsConfig(t *testing.T) {
381382 require .NoError (t , err )
382383 assert .Equal (t , []byte (expectedRouterB ), cfgB .Router )
383384}
385+
386+ // Helper function to create a valid SendRequestedEvent for testing
387+ func createValidSendRequestedEvent (seqNum cciptypes.SeqNum ) * SendRequestedEvent {
388+ return & SendRequestedEvent {
389+ DestChainSelector : chainB ,
390+ SequenceNumber : seqNum ,
391+ Message : cciptypes.Message {
392+ Header : cciptypes.RampMessageHeader {
393+ SourceChainSelector : chainA ,
394+ DestChainSelector : chainB ,
395+ SequenceNumber : seqNum ,
396+ MessageID : cciptypes.Bytes32 {byte (seqNum )},
397+ },
398+ Sender : cciptypes .UnknownAddress ("sender" ),
399+ Receiver : cciptypes .UnknownAddress ("receiver" ),
400+ FeeToken : cciptypes .UnknownAddress ("feeToken" ),
401+ FeeTokenAmount : cciptypes .NewBigInt (big .NewInt (100 )),
402+ },
403+ }
404+ }
405+
406+ func TestMsgsBetweenSeqNums (t * testing.T ) {
407+ tests := []struct {
408+ name string
409+ seqNumRange cciptypes.SeqNumRange
410+ destChainSelector cciptypes.ChainSelector
411+ sequences []types.Sequence
412+ expectedError bool
413+ expectedMsgCount int
414+ validateTxHash func (t * testing.T , msgs []cciptypes.Message )
415+ }{
416+ {
417+ name : "TxHash populated from item.TxHash" ,
418+ seqNumRange : cciptypes .NewSeqNumRange (1 , 3 ),
419+ destChainSelector : chainB ,
420+ sequences : []types.Sequence {
421+ {
422+ Cursor : "100-1-0xabc123" ,
423+ TxHash : []byte {0xab , 0xcd , 0xef , 0x12 , 0x34 , 0x56 },
424+ Data : createValidSendRequestedEvent (1 ),
425+ },
426+ {
427+ Cursor : "100-2-0xdef456" ,
428+ TxHash : []byte {0xde , 0xad , 0xbe , 0xef , 0x78 , 0x90 },
429+ Data : createValidSendRequestedEvent (2 ),
430+ },
431+ },
432+ expectedError : false ,
433+ expectedMsgCount : 2 ,
434+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
435+ require .Len (t , msgs , 2 )
436+ // TxHash should be populated from item.TxHash with 0x prefix
437+ assert .Equal (t , "0xabcdef123456" , msgs [0 ].Header .TxHash )
438+ assert .Equal (t , "0xdeadbeef7890" , msgs [1 ].Header .TxHash )
439+ },
440+ },
441+ {
442+ name : "TxHash extracted from cursor when item.TxHash is empty" ,
443+ seqNumRange : cciptypes .NewSeqNumRange (1 , 2 ),
444+ destChainSelector : chainB ,
445+ sequences : []types.Sequence {
446+ {
447+ Cursor : "100-1-0xfallback111222333444555666777888999000" ,
448+ TxHash : nil , // Empty TxHash
449+ Data : createValidSendRequestedEvent (1 ),
450+ },
451+ {
452+ Cursor : "100-2-0xfallback222333444555666777888999000aaa" ,
453+ TxHash : []byte {}, // Empty TxHash
454+ Data : createValidSendRequestedEvent (2 ),
455+ },
456+ },
457+ expectedError : false ,
458+ expectedMsgCount : 2 ,
459+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
460+ require .Len (t , msgs , 2 )
461+ // TxHash should be extracted from cursor
462+ assert .Equal (t , "0xfallback111222333444555666777888999000" , msgs [0 ].Header .TxHash )
463+ assert .Equal (t , "0xfallback222333444555666777888999000aaa" , msgs [1 ].Header .TxHash )
464+ },
465+ },
466+ {
467+ name : "Mixed: some with item.TxHash, some from cursor" ,
468+ seqNumRange : cciptypes .NewSeqNumRange (1 , 3 ),
469+ destChainSelector : chainB ,
470+ sequences : []types.Sequence {
471+ {
472+ Cursor : "100-1-0xcursor111" ,
473+ TxHash : []byte {0x11 , 0x22 , 0x33 }, // Has TxHash
474+ Data : createValidSendRequestedEvent (1 ),
475+ },
476+ {
477+ Cursor : "100-2-0xcursor222" ,
478+ TxHash : nil , // No TxHash
479+ Data : createValidSendRequestedEvent (2 ),
480+ },
481+ {
482+ Cursor : "100-3-0xcursor333" ,
483+ TxHash : []byte {0x44 , 0x55 , 0x66 }, // Has TxHash
484+ Data : createValidSendRequestedEvent (3 ),
485+ },
486+ },
487+ expectedError : false ,
488+ expectedMsgCount : 3 ,
489+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
490+ require .Len (t , msgs , 3 )
491+ assert .Equal (t , "0x112233" , msgs [0 ].Header .TxHash ) // From item.TxHash
492+ assert .Equal (t , "0xcursor222" , msgs [1 ].Header .TxHash ) // From cursor
493+ assert .Equal (t , "0x445566" , msgs [2 ].Header .TxHash ) // From item.TxHash
494+ },
495+ },
496+ {
497+ name : "Invalid cursor format - TxHash extraction fails gracefully" ,
498+ seqNumRange : cciptypes .NewSeqNumRange (1 , 1 ),
499+ destChainSelector : chainB ,
500+ sequences : []types.Sequence {
501+ {
502+ Cursor : "invalid-cursor" , // Invalid format
503+ TxHash : nil , // No TxHash
504+ Data : createValidSendRequestedEvent (1 ),
505+ },
506+ },
507+ expectedError : false ,
508+ expectedMsgCount : 1 ,
509+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
510+ require .Len (t , msgs , 1 )
511+ // TxHash should be empty when extraction fails
512+ assert .Equal (t , "" , msgs [0 ].Header .TxHash )
513+ },
514+ },
515+ {
516+ name : "Filter out invalid sequence number" ,
517+ seqNumRange : cciptypes .NewSeqNumRange (1 , 2 ),
518+ destChainSelector : chainB ,
519+ sequences : []types.Sequence {
520+ {
521+ Cursor : "100-1-0xabc123" ,
522+ TxHash : []byte {0xab , 0xcd },
523+ Data : createValidSendRequestedEvent (1 ),
524+ },
525+ {
526+ Cursor : "100-2-0xdef456" ,
527+ TxHash : []byte {0xde , 0xef },
528+ Data : createValidSendRequestedEvent (10 ), // Out of range
529+ },
530+ },
531+ expectedError : false ,
532+ expectedMsgCount : 1 ,
533+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
534+ require .Len (t , msgs , 1 )
535+ assert .Equal (t , "0xabcd" , msgs [0 ].Header .TxHash )
536+ },
537+ },
538+ {
539+ name : "Wrong data type in sequence" ,
540+ seqNumRange : cciptypes .NewSeqNumRange (1 , 2 ),
541+ destChainSelector : chainB ,
542+ sequences : []types.Sequence {
543+ {
544+ Cursor : "100-1-0xabc123" ,
545+ TxHash : []byte {0xab , 0xcd },
546+ Data : "invalid data type" , // Not SendRequestedEvent
547+ },
548+ },
549+ expectedError : true ,
550+ expectedMsgCount : 0 ,
551+ validateTxHash : nil ,
552+ },
553+ }
554+
555+ for _ , tt := range tests {
556+ t .Run (tt .name , func (t * testing.T ) {
557+ // Setup mocks
558+ mockReader := reader_mocks .NewMockExtended (t )
559+ mockWriter := writer_mocks .NewMockContractWriter (t )
560+ codec := internal .NewMockAddressCodecHex (t )
561+
562+ accessor := & DefaultAccessor {
563+ lggr : logger .Test (t ),
564+ chainSelector : chainA ,
565+ contractReader : mockReader ,
566+ contractWriter : mockWriter ,
567+ addrCodec : codec ,
568+ }
569+
570+ // Setup mock expectations
571+ mockReader .On ("ExtendedQueryKey" , mock .Anything , mock .Anything ,
572+ mock .Anything , mock .Anything , mock .Anything ).
573+ Return (tt .sequences , nil ).Once ()
574+
575+ // Setup GetBindings mock for GetContractAddress call
576+ // The address string will be converted to bytes by the codec
577+ onRampAddressStr := "0x1234567890abcdef"
578+ onRampAddress := cciptypes.UnknownAddress {0x12 , 0x34 , 0x56 , 0x78 , 0x90 , 0xab , 0xcd , 0xef }
579+ bindings := []contractreader.ExtendedBoundContract {
580+ {
581+ Binding : types.BoundContract {
582+ Name : consts .ContractNameOnRamp ,
583+ Address : onRampAddressStr ,
584+ },
585+ },
586+ }
587+ mockReader .On ("GetBindings" , consts .ContractNameOnRamp ).
588+ Return (bindings ).Once ()
589+
590+ // Execute test
591+ msgs , err := accessor .MsgsBetweenSeqNums (context .Background (), tt .destChainSelector , tt .seqNumRange )
592+
593+ // Verify results
594+ if tt .expectedError {
595+ assert .Error (t , err )
596+ } else {
597+ assert .NoError (t , err )
598+ assert .Len (t , msgs , tt .expectedMsgCount )
599+ if tt .validateTxHash != nil {
600+ tt .validateTxHash (t , msgs )
601+ }
602+ // Verify OnRamp is always set
603+ for _ , msg := range msgs {
604+ assert .Equal (t , onRampAddress , msg .Header .OnRamp )
605+ }
606+ }
607+
608+ // Verify all mock expectations were met
609+ mockReader .AssertExpectations (t )
610+ })
611+ }
612+ }
0 commit comments