@@ -663,6 +663,148 @@ func TestChainFromIntersect(t *testing.T) {
663663 }
664664}
665665
666+ func TestRecentPointsNoDatabase (t * testing.T ) {
667+ // Create a chain manager with no database. Blocks are stored
668+ // in memory only. RecentPoints must return the in-memory
669+ // chain points even though there is no blob store.
670+ cm , err := chain .NewManager (nil , nil )
671+ if err != nil {
672+ t .Fatalf (
673+ "unexpected error creating chain manager: %s" ,
674+ err ,
675+ )
676+ }
677+ c := cm .PrimaryChain ()
678+
679+ // Empty chain should return no points
680+ points := c .RecentPoints (10 )
681+ if len (points ) != 0 {
682+ t .Fatalf (
683+ "expected 0 points on empty chain, got %d" ,
684+ len (points ),
685+ )
686+ }
687+
688+ // Add all test blocks
689+ for _ , testBlock := range testBlocks {
690+ if err := c .AddBlock (testBlock , nil ); err != nil {
691+ t .Fatalf (
692+ "unexpected error adding block to chain: %s" ,
693+ err ,
694+ )
695+ }
696+ }
697+
698+ // Request more points than exist; should get all blocks
699+ points = c .RecentPoints (100 )
700+ if len (points ) != len (testBlocks ) {
701+ t .Fatalf (
702+ "expected %d points, got %d" ,
703+ len (testBlocks ),
704+ len (points ),
705+ )
706+ }
707+
708+ // Points should be in descending order (most recent first)
709+ for i , p := range points {
710+ expectedBlock := testBlocks [len (testBlocks )- 1 - i ]
711+ expectedHash := decodeHex (expectedBlock .MockHash )
712+ if p .Slot != expectedBlock .MockSlot {
713+ t .Fatalf (
714+ "point %d: expected slot %d, got %d" ,
715+ i ,
716+ expectedBlock .MockSlot ,
717+ p .Slot ,
718+ )
719+ }
720+ if string (p .Hash ) != string (expectedHash ) {
721+ t .Fatalf (
722+ "point %d: expected hash %x, got %x" ,
723+ i ,
724+ expectedHash ,
725+ p .Hash ,
726+ )
727+ }
728+ }
729+
730+ // Request fewer points than exist; should get exactly the
731+ // requested count, starting from the tip
732+ points = c .RecentPoints (2 )
733+ if len (points ) != 2 {
734+ t .Fatalf ("expected 2 points, got %d" , len (points ))
735+ }
736+ lastBlock := testBlocks [len (testBlocks )- 1 ]
737+ if points [0 ].Slot != lastBlock .MockSlot {
738+ t .Fatalf (
739+ "first point should be tip: expected slot %d, got %d" ,
740+ lastBlock .MockSlot ,
741+ points [0 ].Slot ,
742+ )
743+ }
744+ secondLastBlock := testBlocks [len (testBlocks )- 2 ]
745+ if points [1 ].Slot != secondLastBlock .MockSlot {
746+ t .Fatalf (
747+ "second point should be tip-1: expected slot %d, got %d" ,
748+ secondLastBlock .MockSlot ,
749+ points [1 ].Slot ,
750+ )
751+ }
752+ }
753+
754+ func TestRecentPointsWithDatabase (t * testing.T ) {
755+ // Create a chain manager with a real database. RecentPoints
756+ // should still return the correct in-memory tip even though
757+ // block storage goes through the blob store.
758+ db := newTestDB (t )
759+ cm , err := chain .NewManager (db , nil )
760+ if err != nil {
761+ t .Fatalf (
762+ "unexpected error creating chain manager: %s" ,
763+ err ,
764+ )
765+ }
766+ c := cm .PrimaryChain ()
767+
768+ // Add all test blocks
769+ for _ , testBlock := range testBlocks {
770+ if err := c .AddBlock (testBlock , nil ); err != nil {
771+ t .Fatalf (
772+ "unexpected error adding block to chain: %s" ,
773+ err ,
774+ )
775+ }
776+ }
777+
778+ // RecentPoints should return points in descending order
779+ points := c .RecentPoints (3 )
780+ if len (points ) != 3 {
781+ t .Fatalf ("expected 3 points, got %d" , len (points ))
782+ }
783+
784+ // Verify descending order by slot
785+ for i := range len (points ) - 1 {
786+ if points [i ].Slot <= points [i + 1 ].Slot {
787+ t .Fatalf (
788+ "points not in descending order: " +
789+ "point %d (slot %d) <= point %d (slot %d)" ,
790+ i , points [i ].Slot ,
791+ i + 1 , points [i + 1 ].Slot ,
792+ )
793+ }
794+ }
795+
796+ // Tip should be the first point
797+ tip := c .Tip ()
798+ if points [0 ].Slot != tip .Point .Slot ||
799+ string (points [0 ].Hash ) != string (tip .Point .Hash ) {
800+ t .Fatalf (
801+ "first point should match tip: got %d.%x, wanted %d.%x" ,
802+ points [0 ].Slot , points [0 ].Hash ,
803+ tip .Point .Slot , tip .Point .Hash ,
804+ )
805+ }
806+ }
807+
666808// mockLedger implements the interface{ SecurityParam() int }
667809// interface used by ChainManager.SetLedger.
668810type mockLedger struct {
0 commit comments