diff --git a/side_loading_test.go b/side_loading_test.go new file mode 100644 index 00000000..db83672f --- /dev/null +++ b/side_loading_test.go @@ -0,0 +1,1029 @@ +//NOTE: This is the integration test file for sideloading. All implementation of the chainDataLoader.Reader +//are to write their custom config and test here. + +package neutrino + +import ( + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcwallet/walletdb" + "github.com/lightninglabs/neutrino/headerfs" + "github.com/lightninglabs/neutrino/headerlist" + "os" + "testing" + "time" +) + +// This is the integration test of the binary file reader. It tests that the +// side laoder along with other components it interacts with, operates as it should. +func TestSideLoadingBinaryImp(t *testing.T) { + SLAtGenesisTip := func(c *Config) { + + c.SideLoad = SideLoadOpt{ + Path: "chainDataLoader/testdata/start_0_end_10_encoded_10_valid_testnet_headers.bin", + Enabled: true, + Verify: false, + SourceType: "binary", + } + + } + + SLAtStartHeight2 := func(c *Config) { + + c.SideLoad = SideLoadOpt{ + Path: "chainDataLoader/testdata/start_2_end_10_encoded_8_valid_regtest_headers.bin", + Enabled: true, + Verify: false, + SourceType: "binary", + } + + c.ChainParams.Net = wire.TestNet + + } + + SLAtEndHeight2 := func(c *Config) { + + c.SideLoad = SideLoadOpt{ + Path: "chainDataLoader/testdata/start_0_end_2_encoded_2_valid_testnet_headers.bin", + Enabled: true, + Verify: false, + SourceType: "binary", + } + + } + + SLInvalidHeaderAtHeight5 := func(c *Config) { + + c.SideLoad = SideLoadOpt{ + Path: "chainDataLoader/testdata/start_0_end_10_encoded_10_invalidHeadersAt5.bin", + Enabled: true, + Verify: false, + SourceType: "binary", + } + + } + + SlAtStartHeight0EndHeight8 := func(c *Config) { + + c.SideLoad = SideLoadOpt{ + Path: "chainDataLoader/testdata/start_0_end_8_encoded_8_valid_testnet_headers.bin", + Enabled: true, + Verify: false, + SourceType: "binary", + } + + } + + testNeutrinoTipAndSLAtGenesis(t, SLAtGenesisTip) + + testNeutrinoTipAheadSLStartHeight(t, SLAtGenesisTip) + + testNeutrinoTipBelowSLStartHeight(t, SLAtStartHeight2) + + testNeutrinoTipGreaterSLEndHeight(t, SLAtEndHeight2) + + testNeutrinoAndSLDiffChain(t, SlAtStartHeight0EndHeight8) + + testNeutrinoSLVerifyTrue(t, SLInvalidHeaderAtHeight5) + + testNeutrinoSLVerifyFalse(t, SLInvalidHeaderAtHeight5) +} + +// testNeutrinoTipAndSLAtGenesis tests that headers are sideloaded when the sideload source and neutrino's tip both start +// at the genesis header. +// Note: The sideload source here should have its start Height at the genesis header height. +func testNeutrinoTipAndSLAtGenesis(t *testing.T, setUpSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test1") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + //tempDir := "/tmp/test12601380815" + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, 40*time.Second, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + setUpSideLoad(c) + + if c.SideLoad.Path == "" { + + t.Errorf("Side load not set up") + + t.FailNow() + } + + svc, err := NewChainService(*c) + defer func() { + err = c.Database.Close() + + if err != nil { + t.Errorf("Error closing database: %v", err) + + t.FailNow() + } + }() + + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + } + + _, initialTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(initialTipHeight) != 0 { + + t.Errorf("Expected chain tip to be at genesis initialTipHeight but of initialTipHeight %v", initialTipHeight) + t.FailNow() + + } + + if svc.blockManager.sideLoadReader == nil { + + t.Errorf("Error initializing side load reader in block manager") + t.FailNow() + } + + if svc.blockManager.sideLoadReader.StartHeight() != 0 { + + t.Errorf("Expected side load source to have headers starting at zero") + t.FailNow() + } + + err = svc.Start() + + if err != nil { + t.Errorf("Error while starting chainservice: %v", err) + t.FailNow() + } + defer func() { + err = svc.Stop() + + if err != nil { + t.Errorf("Error while stopping chainservice: %v", err) + t.FailNow() + } + }() + + time.Sleep(1 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(finalTipHeight) != svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected chain tip to be of finalTipHeight %v but of finalTipHeight %v", + svc.blockManager.sideLoadReader.EndHeight(), finalTipHeight) + t.FailNow() + + } + + if svc.chainParams.Net != svc.blockManager.sideLoadReader.HeadersChain() { + + t.Errorf("Expected side load source and chain params to be on same network chain") + t.FailNow() + } + + if int64(initialTipHeight) >= svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected chain tip to have headers behind side load source's end height") + t.FailNow() + } +} + +// testNeutrinoTipAheadSLStartHeight tests sideloading when Neutrino's tip is ahead of the sideload source's startHeight. +// NOTE: The sideload source to be used here should have its startHeight below 2. +func testNeutrinoTipAheadSLStartHeight(t *testing.T, setUpSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test2") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, dbOpenTimeout, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + setUpSideLoad(c) + + svc, err := NewChainService(*c) + defer func() { + err = c.Database.Close() + + if err != nil { + t.Errorf("Error closing database: %v", err) + + t.FailNow() + } + }() + + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + } + + err = svc.BlockHeaders.WriteHeaders([]headerfs.BlockHeader{ + { + Height: 1, + BlockHeader: &wire.BlockHeader{}, + }, + + { + Height: 2, + BlockHeader: &wire.BlockHeader{}, + }, + }...) + + if err != nil { + + t.Errorf("Error writing headers for test: %v", err) + + t.FailNow() + } + + _, initialTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(initialTipHeight) != 2 { + + t.Errorf("Expected chain tip to be at tipHeight 2 but of tipHeight %v", initialTipHeight) + t.FailNow() + + } + + svc.blockManager.headerTip = initialTipHeight + + svc.blockManager.headerList.ResetHeaderState(headerlist.Node{ + Height: int32(initialTipHeight), + }) + + sideLoadStartHeight := svc.blockManager.sideLoadReader.StartHeight() + + if int64(initialTipHeight) <= sideLoadStartHeight { + + t.Errorf("Expected chain tip to have headers ahead of chain tip source") + t.FailNow() + } + + err = svc.Start() + + if err != nil { + t.Errorf("Error while starting chainservice: %v", err) + t.FailNow() + } + defer func() { + err = svc.Stop() + + if err != nil { + t.Errorf("Error while stopping chainservice: %v", err) + t.FailNow() + } + }() + + time.Sleep(1 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + sideLoadEndHeight := svc.blockManager.sideLoadReader.EndHeight() + + if int64(finalTipHeight) != sideLoadEndHeight { + + t.Errorf("Expected chain tip to be of height, %v but got %v", sideLoadEndHeight, finalTipHeight) + t.FailNow() + } + + if svc.chainParams.Net != svc.blockManager.sideLoadReader.HeadersChain() { + + t.Errorf("Expected side load source and chain params to be on same network chain") + t.FailNow() + } + + if int64(initialTipHeight) >= svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected chain tip to have headers behind side load source's end height") + t.FailNow() + } +} + +// testNeutrinoTipBelowSLStartHeight tests sideloading when Neutrino's tip is below the side load source's startHeight. +// NOTE: The sideload source to be used here should have its startHeight higher than the genesis header height. +func testNeutrinoTipBelowSLStartHeight(t *testing.T, setUpSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test3") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, dbOpenTimeout, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + setUpSideLoad(c) + + svc, err := NewChainService(*c) + defer func() { + err = c.Database.Close() + + if err != nil { + t.Errorf("Error closing database: %v", err) + + t.FailNow() + } + }() + + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + + } + + _, tipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + sideLoadStartHeight := svc.blockManager.sideLoadReader.StartHeight() + + if int64(tipHeight) >= sideLoadStartHeight { + + t.Errorf("Expected chain tip to have headers behind side load source") + } + + err = svc.Start() + + if err != nil { + t.Errorf("Error while starting chainservice: %v", err) + t.FailNow() + } + defer func() { + err = svc.Stop() + + if err != nil { + t.Errorf("Error while stopping chainservice: %v", err) + t.FailNow() + } + }() + + time.Sleep(1 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if finalTipHeight != tipHeight { + + t.Errorf("Expected no headers be written to the DB from side load") + t.FailNow() + } +} + +// testNeutrinoTipGreaterSLEndHeight tests sideloading when Neutrino's tip is greater than the side load source's end +// Height. +// NOTE: The sideload source to be used here should have its EndHeight below 4. +func testNeutrinoTipGreaterSLEndHeight(t *testing.T, setUpSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test4") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, dbOpenTimeout, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + setUpSideLoad(c) + + if c.SideLoad.Path == "" { + + t.Errorf("Side load not set up") + } + + svc, err := NewChainService(*c) + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + + } + defer func() { + err = c.Database.Close() + + if err != nil { + t.Errorf("Error closing database: %v", err) + + t.FailNow() + } + }() + + err = svc.BlockHeaders.WriteHeaders([]headerfs.BlockHeader{ + { + Height: 1, + BlockHeader: &wire.BlockHeader{}, + }, + + { + Height: 2, + BlockHeader: &wire.BlockHeader{}, + }, + { + Height: 3, + BlockHeader: &wire.BlockHeader{}, + }, + { + Height: 4, + BlockHeader: &wire.BlockHeader{}, + }, + }...) + + if err != nil { + + t.Errorf("Error writing headers to DB for test") + + t.FailNow() + } + + _, initialTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(initialTipHeight) != 4 { + + t.Errorf("Expected chain tip to be at tipHeight 2 but of tipHeight %v", initialTipHeight) + t.FailNow() + + } + + svc.blockManager.headerTip = initialTipHeight + + svc.blockManager.headerList.ResetHeaderState(headerlist.Node{ + Height: int32(initialTipHeight), + }) + + if svc.blockManager.sideLoadReader == nil { + + t.Errorf("Error initializing side load reader in block manager") + t.FailNow() + } + + sideLoadEndHeight := svc.blockManager.sideLoadReader.EndHeight() + + if int64(initialTipHeight) <= sideLoadEndHeight { + + t.Errorf("Expected chain tip to have headers ahead of side load source's end height"+ + "Tip height: %v while sideLoadEndHeight: %v", initialTipHeight, sideLoadEndHeight) + t.FailNow() + } + + sideLoadStartHeight := svc.blockManager.sideLoadReader.StartHeight() + + if int64(initialTipHeight) < sideLoadStartHeight { + + t.Errorf("Expected chain tip to be greater than or equal to source file") + t.FailNow() + } + + err = svc.Start() + + if err != nil { + t.Errorf("Error while starting chainservice: %v", err) + t.FailNow() + } + defer func() { + err = svc.Stop() + + if err != nil { + t.Errorf("Error while stopping chainservice: %v", err) + t.FailNow() + } + }() + + time.Sleep(1 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if finalTipHeight != initialTipHeight { + + t.Errorf("Expected no headers be written to the DB from side load"+ + "initialTipHeight: %v and finalTipHeight: %v", initialTipHeight, finalTipHeight) + t.FailNow() + } +} + +// testNeutrinoAndSLDiffChain tests sideloading when the sideload source has headers on a different chain from +// the chain's. +// NOTE: The sideload source header to be used here should be on a bitcoin network other than wire.TestNet3. +func testNeutrinoAndSLDiffChain(t *testing.T, setUpSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test5") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, dbOpenTimeout, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + setUpSideLoad(c) + + c.ChainParams.Net = wire.SimNet + + svc, err := NewChainService(*c) + defer func() { + err = c.Database.Close() + + if err != nil { + t.Errorf("Error closing database: %v", err) + + t.FailNow() + } + }() + + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + + } + + if svc.chainParams.Net == svc.blockManager.sideLoadReader.HeadersChain() { + + t.Errorf("Expected side load source and chain params to have differnt network chain") + t.FailNow() + } + + _, initialTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(initialTipHeight) >= svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected chain tip to have headers behind side load source's end height") + t.FailNow() + } + + sideLoadStartHeight := svc.blockManager.sideLoadReader.StartHeight() + if int64(initialTipHeight) < sideLoadStartHeight { + + t.Errorf("Expected chain tip to have headers ahead of chain tip source"+ + "TipHeight: %v, SideLoad Start Height: %v", initialTipHeight, sideLoadStartHeight) + t.FailNow() + } + + err = svc.Start() + + if err != nil { + t.Errorf("Error while starting chainservice: %v", err) + t.FailNow() + } + defer func() { + err = svc.Stop() + + if err != nil { + t.Errorf("Error while stopping chainservice: %v", err) + t.FailNow() + } + }() + + time.Sleep(1 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if finalTipHeight != initialTipHeight { + + t.Errorf("Expected no headers be written to the DB from side load."+ + "initialTipHeight: %v, finalTipHeight: %v", initialTipHeight, finalTipHeight) + t.FailNow() + } +} + +// testNeutrinoSLVerifyTrue tests sideloading when verifying headers is enabled. +// NOTE: The sideload source to be used here should have invalid headers at some point (not at the first header though). +// The sideload config's Verify field should be set to true and the same sidelaod source used here should be used in the +// testNeutrinoSLVerifyFalse for contrast. +func testNeutrinoSLVerifyTrue(t *testing.T, setUpInValidSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test6") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, dbOpenTimeout, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + setUpInValidSideLoad(c) + + c.SideLoad.Verify = true + + if !c.SideLoad.Verify { + + t.Errorf("Expected verification true") + t.FailNow() + } + + svc, err := NewChainService(*c) + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + + } + defer func() { + err = c.Database.Close() + + if err != nil { + t.Errorf("Error closing database: %v", err) + + t.FailNow() + } + }() + + if svc.chainParams.Net != svc.blockManager.sideLoadReader.HeadersChain() { + + t.Errorf("Expected side load source and chain params to have same network chain") + t.FailNow() + } + + _, initialTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(initialTipHeight) > svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected chain tip to have headers behind side load source's end height") + t.FailNow() + } + + sideLoadStartHeight := svc.blockManager.sideLoadReader.StartHeight() + if int64(initialTipHeight) < sideLoadStartHeight { + + t.Errorf("Expected chain tip to have headers ahead or equal to side load source") + t.FailNow() + } + + err = svc.Start() + + if err != nil { + + t.Errorf("Error starting chainservice") + + t.FailNow() + } + + defer func() { + err = svc.Stop() + if err != nil { + t.Errorf("error stopping chain service: %v", err) + + t.FailNow() + } + }() + + time.Sleep(2 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if finalTipHeight != initialTipHeight { + + t.Errorf("Expected no header written to db"+ + "initialTipHeight: %v, finalTipHeight: %v", initialTipHeight, finalTipHeight) + t.FailNow() + } + + if int64(finalTipHeight) == svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected final height not to equate side loader's end height.") + t.FailNow() + } +} + +// testNeutrinoSLVerifyFalse tests sideloading when verifying headers is disabled in contrast to the +// testNeutrinoSLVerifyTrue testcase. +// NOTE: The sideload source to be used here should have invalid headers at some point (not at the first header though). +// The sideload config's Verify field should be set to false and the same sideload source used here should be used in the +// testNeutrinoSLVerifyTrue for contrast. +func testNeutrinoSLVerifyFalse(t *testing.T, setUpInValidSideLoad func(config *Config)) { + tempDir, err := os.MkdirTemp("", "test7") + defer func() { + err := os.RemoveAll(tempDir) + if err != nil { + t.Errorf("error removing tempDir: %v", err) + } + }() + + if err != nil { + t.Errorf("error making temp directory: %v", err) + + t.FailNow() + } + db, err := walletdb.Create( + "bdb", tempDir+"/weks.db", true, dbOpenTimeout, + ) + if err != nil { + t.Errorf("error creating wallet: %v", err) + + t.FailNow() + } + + c := &Config{ + DataDir: tempDir, + Database: db, + ChainParams: chaincfg.TestNet3Params, + } + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + if c.SideLoad.Verify { + + t.Errorf("Expected verification false") + t.FailNow() + } + + setUpInValidSideLoad(c) + + if err != nil { + t.Errorf("Error during start up: %v", err) + t.FailNow() + } + + svc, err := NewChainService(*c) + + defer func() { + err = c.Database.Close() + + if err != nil { + + t.Errorf("Error closing DB") + + t.FailNow() + } + }() + + if err != nil { + + t.Errorf("Error during chain service creation: %v", err) + t.FailNow() + + } + + if svc.chainParams.Net != svc.blockManager.sideLoadReader.HeadersChain() { + + t.Errorf("Expected side load source and chain params to have same network chain") + t.FailNow() + } + + _, initialTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(initialTipHeight) >= svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected chain tip to have headers behind side load source's end height") + t.FailNow() + } + + sideLoadStartHeight := svc.blockManager.sideLoadReader.StartHeight() + if int64(initialTipHeight) < sideLoadStartHeight { + + t.Errorf("Expected chain tip to have headers ahead or equal to side load source") + t.FailNow() + } + + err = svc.Start() + + if err != nil { + t.Errorf("Error while starting chainservice: %v", err) + t.FailNow() + } + defer func() { + err = svc.Stop() + + if err != nil { + t.Errorf("Error while stopping chainservice: %v", err) + t.FailNow() + } + }() + + time.Sleep(1 * time.Second) + + _, finalTipHeight, err := svc.BlockHeaders.ChainTip() + + if err != nil { + + t.Errorf("Error while fetching chain tip: %v", err) + t.FailNow() + } + + if int64(finalTipHeight) != svc.blockManager.sideLoadReader.EndHeight() { + + t.Errorf("Expected header height to be same as side load") + t.FailNow() + } +}