@@ -3,6 +3,7 @@ package chainaccessor
33import (
44 "context"
55 "fmt"
6+ "math/big"
67 "reflect"
78 "testing"
89
@@ -381,3 +382,206 @@ 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 : "Mixed: some with item.TxHash, some without" ,
443+ seqNumRange : cciptypes .NewSeqNumRange (1 , 3 ),
444+ destChainSelector : chainB ,
445+ sequences : []types.Sequence {
446+ {
447+ Cursor : "100-1-0xcursor111" ,
448+ TxHash : []byte {0x11 , 0x22 , 0x33 }, // Has TxHash
449+ Data : createValidSendRequestedEvent (1 ),
450+ },
451+ {
452+ Cursor : "100-2-0xcursor222" ,
453+ TxHash : nil , // No TxHash
454+ Data : createValidSendRequestedEvent (2 ),
455+ },
456+ {
457+ Cursor : "100-3-0xcursor333" ,
458+ TxHash : []byte {0x44 , 0x55 , 0x66 }, // Has TxHash
459+ Data : createValidSendRequestedEvent (3 ),
460+ },
461+ },
462+ expectedError : false ,
463+ expectedMsgCount : 3 ,
464+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
465+ require .Len (t , msgs , 3 )
466+ assert .Equal (t , "0x112233" , msgs [0 ].Header .TxHash ) // From item.TxHash
467+ assert .Equal (t , "" , msgs [1 ].Header .TxHash ) // Empty - no TxHash provided
468+ assert .Equal (t , "0x445566" , msgs [2 ].Header .TxHash ) // From item.TxHash
469+ },
470+ },
471+ {
472+ name : "Empty TxHash when item.TxHash is not provided" ,
473+ seqNumRange : cciptypes .NewSeqNumRange (1 , 1 ),
474+ destChainSelector : chainB ,
475+ sequences : []types.Sequence {
476+ {
477+ Cursor : "100-1-0xabc123" ,
478+ TxHash : nil , // No TxHash
479+ Data : createValidSendRequestedEvent (1 ),
480+ },
481+ },
482+ expectedError : false ,
483+ expectedMsgCount : 1 ,
484+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
485+ require .Len (t , msgs , 1 )
486+ // TxHash should be empty when item.TxHash is not provided
487+ assert .Equal (t , "" , msgs [0 ].Header .TxHash )
488+ },
489+ },
490+ {
491+ name : "Filter out invalid sequence number" ,
492+ seqNumRange : cciptypes .NewSeqNumRange (1 , 2 ),
493+ destChainSelector : chainB ,
494+ sequences : []types.Sequence {
495+ {
496+ Cursor : "100-1-0xabc123" ,
497+ TxHash : []byte {0xab , 0xcd },
498+ Data : createValidSendRequestedEvent (1 ),
499+ },
500+ {
501+ Cursor : "100-2-0xdef456" ,
502+ TxHash : []byte {0xde , 0xef },
503+ Data : createValidSendRequestedEvent (10 ), // Out of range
504+ },
505+ },
506+ expectedError : false ,
507+ expectedMsgCount : 1 ,
508+ validateTxHash : func (t * testing.T , msgs []cciptypes.Message ) {
509+ require .Len (t , msgs , 1 )
510+ assert .Equal (t , "0xabcd" , msgs [0 ].Header .TxHash )
511+ },
512+ },
513+ {
514+ name : "Wrong data type in sequence" ,
515+ seqNumRange : cciptypes .NewSeqNumRange (1 , 2 ),
516+ destChainSelector : chainB ,
517+ sequences : []types.Sequence {
518+ {
519+ Cursor : "100-1-0xabc123" ,
520+ TxHash : []byte {0xab , 0xcd },
521+ Data : "invalid data type" , // Not SendRequestedEvent
522+ },
523+ },
524+ expectedError : true ,
525+ expectedMsgCount : 0 ,
526+ validateTxHash : nil ,
527+ },
528+ }
529+
530+ for _ , tt := range tests {
531+ t .Run (tt .name , func (t * testing.T ) {
532+ // Setup mocks
533+ mockReader := reader_mocks .NewMockExtended (t )
534+ mockWriter := writer_mocks .NewMockContractWriter (t )
535+ codec := internal .NewMockAddressCodecHex (t )
536+
537+ accessor := & DefaultAccessor {
538+ lggr : logger .Test (t ),
539+ chainSelector : chainA ,
540+ contractReader : mockReader ,
541+ contractWriter : mockWriter ,
542+ addrCodec : codec ,
543+ }
544+
545+ // Setup mock expectations
546+ mockReader .On ("ExtendedQueryKey" , mock .Anything , mock .Anything ,
547+ mock .Anything , mock .Anything , mock .Anything ).
548+ Return (tt .sequences , nil ).Once ()
549+
550+ // Setup GetBindings mock for GetContractAddress call
551+ // The address string will be converted to bytes by the codec
552+ onRampAddressStr := "0x1234567890abcdef"
553+ onRampAddress := cciptypes.UnknownAddress {0x12 , 0x34 , 0x56 , 0x78 , 0x90 , 0xab , 0xcd , 0xef }
554+ bindings := []contractreader.ExtendedBoundContract {
555+ {
556+ Binding : types.BoundContract {
557+ Name : consts .ContractNameOnRamp ,
558+ Address : onRampAddressStr ,
559+ },
560+ },
561+ }
562+ mockReader .On ("GetBindings" , consts .ContractNameOnRamp ).
563+ Return (bindings ).Once ()
564+
565+ // Execute test
566+ msgs , err := accessor .MsgsBetweenSeqNums (context .Background (), tt .destChainSelector , tt .seqNumRange )
567+
568+ // Verify results
569+ if tt .expectedError {
570+ assert .Error (t , err )
571+ } else {
572+ assert .NoError (t , err )
573+ assert .Len (t , msgs , tt .expectedMsgCount )
574+ if tt .validateTxHash != nil {
575+ tt .validateTxHash (t , msgs )
576+ }
577+ // Verify OnRamp is always set
578+ for _ , msg := range msgs {
579+ assert .Equal (t , onRampAddress , msg .Header .OnRamp )
580+ }
581+ }
582+
583+ // Verify all mock expectations were met
584+ mockReader .AssertExpectations (t )
585+ })
586+ }
587+ }
0 commit comments