From 2e234f7ff1218506a4b90064350b6c3bacb43238 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 07:29:35 +0100 Subject: [PATCH 01/11] temp change Signed-off-by: Ononiwu Maureen --- go.mod | 2 ++ go.sum | 4 ++-- itest/lnd_neutrino_sideload.go | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 itest/lnd_neutrino_sideload.go diff --git a/go.mod b/go.mod index 54548e6635..24e28b80f3 100644 --- a/go.mod +++ b/go.mod @@ -205,3 +205,5 @@ replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-d go 1.19 retract v0.0.2 + +replace github.com/lightninglabs/neutrino => github.com/chinwendu20/neutrino v0.0.0-20240325184234-41da32452de5 diff --git a/go.sum b/go.sum index 9c1aa38e48..36e0083c00 100644 --- a/go.sum +++ b/go.sum @@ -122,6 +122,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chinwendu20/neutrino v0.0.0-20240325184234-41da32452de5 h1:K+H1psGIUP9Xx43TkfkT5c22928uqGiq2DJ2tnGhuhk= +github.com/chinwendu20/neutrino v0.0.0-20240325184234-41da32452de5/go.mod h1:q5cAgGBV6xn6yWE0TnHG/1911f6aXjSRmAzgSucbaZQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -408,8 +410,6 @@ github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= -github.com/lightninglabs/neutrino v0.16.0 h1:YNTQG32fPR/Zg0vvJVI65OBH8l3U18LSXXtX91hx0q0= -github.com/lightninglabs/neutrino v0.16.0/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk= github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g= github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo= github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display h1:pRdza2wleRN1L2fJXd6ZoQ9ZegVFTAb2bOQfruJPKcY= diff --git a/itest/lnd_neutrino_sideload.go b/itest/lnd_neutrino_sideload.go new file mode 100644 index 0000000000..116bd6dd91 --- /dev/null +++ b/itest/lnd_neutrino_sideload.go @@ -0,0 +1 @@ +package itest From 9c00e58566de856238a48ef48c3b4e5727785f31 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 07:30:13 +0100 Subject: [PATCH 02/11] lnrpc: rename file file_utils.go -> utils.go Signed-off-by: Ononiwu Maureen --- lnrpc/{file_utils.go => utils.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lnrpc/{file_utils.go => utils.go} (100%) diff --git a/lnrpc/file_utils.go b/lnrpc/utils.go similarity index 100% rename from lnrpc/file_utils.go rename to lnrpc/utils.go From 7254fb6d55d8962d03e54c707ec78e894f5e0ece Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 11:19:37 +0100 Subject: [PATCH 03/11] lnrpc: Add new utils functions. Signed-off-by: Ononiwu Maureen --- lnrpc/utils.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lnrpc/utils.go b/lnrpc/utils.go index ffb83fbf17..19b5e996ea 100644 --- a/lnrpc/utils.go +++ b/lnrpc/utils.go @@ -1,6 +1,10 @@ package lnrpc import ( + "fmt" + "io" + "net/http" + "net/url" "os" ) @@ -13,3 +17,38 @@ func FileExists(name string) bool { } return true } + +// IsValidURL checks if the given text is a valid URL. +// Passed text must have a scheme of "http" or "https" format to be valid. +func IsValidURL(text string) bool { + parsedURL, err := url.Parse(text) + if err != nil { + return false + } + + // Consider it a valid URL if it has a scheme of http or https. + return parsedURL.Scheme == "http" || parsedURL.Scheme == "https" +} + +// FetchURL returns the content fetched from the specified URL in bytes. +func FetchURL(url string) ([]byte, error) { + // Perform the HTTP GET request. + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("fetching URL failed: %w", err) + } + defer resp.Body.Close() + + // Check the HTTP response status. + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("bad status code: %d", resp.StatusCode) + } + + // Read the response body. + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("reading response body failed: %w", err) + } + + return body, nil +} From 9a230aa7eab4f6203eadea308a90189cfdecafc6 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 11:39:59 +0100 Subject: [PATCH 04/11] lncfg: Add new SideloadOpt to neutrino config Signed-off-by: Ononiwu Maureen --- lncfg/neutrino.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lncfg/neutrino.go b/lncfg/neutrino.go index 09a66312aa..116bb7b443 100644 --- a/lncfg/neutrino.go +++ b/lncfg/neutrino.go @@ -1,6 +1,20 @@ package lncfg -import "time" +import ( + "time" +) + +// SideloadOpt holds the configuration options for sideloading headers in +// neutrino. +// +//nolint:lll +type SideloadOpt struct { + Enable bool `long:"enable" description:"Indicates sideloading is enabled"` + SourceType string `long:"sourceType" description:"Indicates the encoding format of the sideload source" choice:"binary"` + SourcePath string `long:"sourcePath" description:"Indicates the path to the sideload source"` + SkipVerify bool `long:"skipVerify" description:"Indicates if to verify headers while sideleoading"` + SideloadRange uint32 `long:"range" description:"Indicates how much headers should be read from the source at a time"` +} // Neutrino holds the configuration options for the daemon's connection to // neutrino. @@ -19,4 +33,5 @@ type Neutrino struct { ValidateChannels bool `long:"validatechannels" description:"Validate every channel in the graph during sync by downloading the containing block. This is the inverse of routing.assumechanvalid, meaning that for Neutrino the validation is turned off by default for massively increased graph sync performance. This speedup comes at the risk of using an unvalidated view of the network for routing. Overwrites the value of routing.assumechanvalid if Neutrino is used. (default: false)"` BroadcastTimeout time.Duration `long:"broadcasttimeout" description:"The amount of time to wait before giving up on a transaction broadcast attempt."` PersistFilters bool `long:"persistfilters" description:"Whether compact filters fetched from the P2P network should be persisted to disk."` + BlkHdrSideloadOpt *SideloadOpt `group:"sideload" namespace:"sideload"` } From 1b2d2736d5c9586d9edf9ea50b4291fe252cfa62 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 11:53:36 +0100 Subject: [PATCH 05/11] lncfg: Validate SideloadOpt and neutrino cfg Signed-off-by: Ononiwu Maureen --- lncfg/neutrino.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/lncfg/neutrino.go b/lncfg/neutrino.go index 116bb7b443..2b12a22817 100644 --- a/lncfg/neutrino.go +++ b/lncfg/neutrino.go @@ -2,6 +2,9 @@ package lncfg import ( "time" + + "github.com/go-errors/errors" + "github.com/lightningnetwork/lnd/lnrpc" ) // SideloadOpt holds the configuration options for sideloading headers in @@ -35,3 +38,62 @@ type Neutrino struct { PersistFilters bool `long:"persistfilters" description:"Whether compact filters fetched from the P2P network should be persisted to disk."` BlkHdrSideloadOpt *SideloadOpt `group:"sideload" namespace:"sideload"` } + +// Validate checks a Neutrino instance's config for correctness, returning nil +// if the instance is uninitialized or its sideload options are valid. Errors +// from sideload option validation are returned. +func (n *Neutrino) Validate() error { + if n == nil { + // Consider nil instance as uninitialized; no validation needed. + return nil + } + + // Validate sideload options. + err := n.BlkHdrSideloadOpt.Validate() + if err != nil { + return err // Return validation errors. + } + + return nil +} + +// Validate checks SideloadOpt for required source type and path, returning +// errors if they're missing or invalid. +func (s *SideloadOpt) Validate() error { + if !s.Enable { + return nil + } + + // Require source type for sideloading. + if s.SourceType == "" { + return errors.New("source type required for sideloading " + + "headers.") + } + + // Require source path for sideloading. + if s.SourcePath == "" { + return errors.New("source path required for sideloading " + + "headers.") + } + + // Check source path validity. + if !validatePath(s.SourcePath) { + return errors.New("invalid source path") + } + + return nil +} + +// validatePath verifies if a path is a valid URL or an existing file, returning +// true if valid. +func validatePath(path string) bool { + // Check path validity as URL. + if lnrpc.IsValidURL(path) { + return true + } + + // Clean/expand the path; check file existence. + path = CleanAndExpandPath(path) + + return lnrpc.FileExists(path) +} From 57dc6bb33ff69128567b38bad3290b266dbfe494 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 11:24:15 +0100 Subject: [PATCH 06/11] lnd: Validate neutrino config build Signed-off-by: Ononiwu Maureen --- config.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index f9aec0284d..6433fb01d9 100644 --- a/config.go +++ b/config.go @@ -1260,8 +1260,10 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, "credentials for bitcoind: %v", err) } case neutrinoBackendName: - // No need to get RPC parameters. - + err = cfg.NeutrinoMode.Validate() + if err != nil { + return nil, mkErr(err.Error()) + } case "nochainbackend": // Nothing to configure, we're running without any chain // backend whatsoever (pure signing mode). From 9cf2e8f36649a09cb314744a91798754796a25d4 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 11:27:04 +0100 Subject: [PATCH 07/11] lnd: Parse SideloadOpt for neutrino init Signed-off-by: Ononiwu Maureen --- config_builder.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/config_builder.go b/config_builder.go index 7c4599fb85..17cb19704e 100644 --- a/config_builder.go +++ b/config_builder.go @@ -6,6 +6,8 @@ import ( "database/sql" "errors" "fmt" + "github.com/lightninglabs/neutrino/sideload" + "io" "io/ioutil" "net" "os" @@ -1410,6 +1412,15 @@ func initNeutrinoBackend(ctx context.Context, cfg *Config, chainDir string, PersistToDisk: cfg.NeutrinoMode.PersistFilters, } + blkHdrSideload, err := parseSideloadOpt( + cfg.NeutrinoMode.BlkHdrSideloadOpt, + ) + if err != nil { + return nil, nil, err + } + + config.BlkHdrSideload = blkHdrSideload + neutrino.MaxPeers = 8 neutrino.BanDuration = time.Hour * 48 neutrino.UserAgentName = cfg.NeutrinoMode.UserAgentName @@ -1438,6 +1449,49 @@ func initNeutrinoBackend(ctx context.Context, cfg *Config, chainDir string, return neutrinoCS, cleanUp, nil } +// parseSideloadOpt converts lncfg.SideloadOpt to neutrino.SideloadOpt. +func parseSideloadOpt(opt *lncfg.SideloadOpt) (*neutrino.SideloadOpt, error) { + if !opt.Enable { + return nil, nil + } + + var reader io.ReadSeeker + if lnrpc.IsValidURL(opt.SourcePath) { + resp, err := lnrpc.FetchURL(opt.SourcePath) + if err != nil { + return nil, fmt.Errorf( + "failed to fetch URL source path for "+ + "sideloading: %v", err) + } + + // Create a bytes.Reader over the response body, + // which implements io.ReadSeeker. + reader = bytes.NewReader(resp) + } else { + file, err := os.Open(opt.SourcePath) + if err != nil { + return nil, fmt.Errorf( + "failed to open file for sideloading: %v", err) + } + + reader = file + } + + var source sideload.SourceType + + err := source.UnmarshalText([]byte(opt.SourceType)) + if err != nil { + return nil, err + } + + return &neutrino.SideloadOpt{ + SourceType: source, + Reader: reader, + SkipVerify: opt.SkipVerify, + SideloadRange: opt.SideloadRange, + }, nil +} + // parseHeaderStateAssertion parses the user-specified neutrino header state // into a headerfs.FilterHeader. func parseHeaderStateAssertion(state string) (*headerfs.FilterHeader, error) { From 198491797360f23dd87c16b63a039e3c1d302cfc Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 19:08:31 +0100 Subject: [PATCH 08/11] lntest: Add header gen for neutrino sideload test Signed-off-by: Ononiwu Maureen --- lntest/utils.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lntest/utils.go b/lntest/utils.go index 660c42ef92..62e6063ac1 100644 --- a/lntest/utils.go +++ b/lntest/utils.go @@ -1,14 +1,19 @@ package lntest import ( + "bytes" "fmt" "io" "math" "os" "strconv" "strings" + "sync" + "testing" "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnrpc" @@ -16,6 +21,7 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" + "github.com/stretchr/testify/require" ) const ( @@ -272,3 +278,34 @@ func CalcStaticFeeBuffer(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount { return feeBuffer.ToSatoshis() } + +func GenerateBlockHeaderBytes(numHeaders uint32, harness *rpctest.Harness, + t *testing.T) []byte { + + blockHashes, err := harness.Client.Generate(numHeaders) + require.NoError(t, err) + + return serializeHeaders(blockHashes, harness, t) +} + +var headerBufPool = sync.Pool{ + New: func() interface{} { return new(bytes.Buffer) }, +} + +func serializeHeaders(blockHashes []*chainhash.Hash, + harness *rpctest.Harness, t *testing.T) []byte { + + headerBuf := headerBufPool.Get().(*bytes.Buffer) + headerBuf.Reset() + defer headerBufPool.Put(headerBuf) + + for i := range blockHashes { + hdr, err := harness.Client.GetBlockHeader(blockHashes[i]) + require.NoError(t, err) + + err = hdr.Serialize(headerBuf) + require.NoError(t, err) + } + + return headerBuf.Bytes() +} From c0e48dcd328449b2dae68fe8a1eb51b92ef21f31 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 19:13:16 +0100 Subject: [PATCH 09/11] lntest: Add arg/tag for conditional sideload Signed-off-by: Ononiwu Maureen --- lntest/neutrino.go | 10 +++++++--- lntest/neutrino_default.go | 13 +++++++++++++ lntest/neutrino_sideload.go | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 lntest/neutrino_default.go create mode 100644 lntest/neutrino_sideload.go diff --git a/lntest/neutrino.go b/lntest/neutrino.go index 11f13612f8..895fd19d37 100644 --- a/lntest/neutrino.go +++ b/lntest/neutrino.go @@ -14,6 +14,7 @@ import ( // backed by a neutrino node. type NeutrinoBackendConfig struct { minerAddr string + sideload bool } // A compile time assertion to ensure NeutrinoBackendConfig meets the @@ -25,7 +26,9 @@ var _ node.BackendConfig = (*NeutrinoBackendConfig)(nil) func (b NeutrinoBackendConfig) GenArgs() []string { var args []string args = append(args, "--bitcoin.node=neutrino") - args = append(args, "--neutrino.connect="+b.minerAddr) + if !b.sideload { + args = append(args, "--neutrino.connect="+b.minerAddr) + } // We enable validating channels so that we can obtain the outpoint for // channels within the graph and make certain assertions based on them. args = append(args, "--neutrino.validatechannels") @@ -54,12 +57,13 @@ func (b NeutrinoBackendConfig) Name() string { return NeutrinoBackendName } -// NewBackend starts and returns a NeutrinoBackendConfig for the node. -func NewBackend(miner string, _ *chaincfg.Params) ( +// newBackend starts and returns a NeutrinoBackendConfig for the node. +func newBackend(miner string, sideload bool, _ *chaincfg.Params) ( *NeutrinoBackendConfig, func() error, error) { bd := &NeutrinoBackendConfig{ minerAddr: miner, + sideload: sideload, } cleanUp := func() error { return nil } diff --git a/lntest/neutrino_default.go b/lntest/neutrino_default.go new file mode 100644 index 0000000000..f60fb15270 --- /dev/null +++ b/lntest/neutrino_default.go @@ -0,0 +1,13 @@ +//go:build neutrino && !sideload +// +build neutrino,!sideload + +package lntest + +import "github.com/btcsuite/btcd/chaincfg" + +// NewBackend starts and returns a NeutrinoBackendConfig for the node. +func NewBackend(miner string, params *chaincfg.Params) ( + *NeutrinoBackendConfig, func() error, error) { + + return newBackend(miner, false, params) +} diff --git a/lntest/neutrino_sideload.go b/lntest/neutrino_sideload.go new file mode 100644 index 0000000000..fe1f04564e --- /dev/null +++ b/lntest/neutrino_sideload.go @@ -0,0 +1,15 @@ +//go:build neutrino && sideload +// +build neutrino,sideload + +package lntest + +import ( + "github.com/btcsuite/btcd/chaincfg" +) + +// NewBackend starts and returns a NeutrinoBackendConfig for the node. +func NewBackend(miner string, params *chaincfg.Params) ( + *NeutrinoBackendConfig, func() error, error) { + + return newBackend(miner, true, params) +} From dab9d3474e508eb9c6832b06ee0d6f04b7afb442 Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 19:15:13 +0100 Subject: [PATCH 10/11] lntest: Add check for sideload test func Signed-off-by: Ononiwu Maureen --- lntest/harness.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lntest/harness.go b/lntest/harness.go index 1b9d18faec..3b65952919 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -161,6 +161,20 @@ func (h *HarnessTest) ChainBackendName() string { return h.manager.chainBackend.Name() } +func (h *HarnessTest) IsNeutrinoSideloadTest() bool { + if !(h.manager.chainBackend.Name() == NeutrinoBackendName) { + return false + } + + for _, s := range h.manager.chainBackend.GenArgs() { + if s == "--neutrino.connect="+h.Miner.P2PAddress() { + return false + } + } + + return true +} + // Context returns the run context used in this test. Usaually it should be // managed by the test itself otherwise undefined behaviors will occur. It can // be used, however, when a test needs to have its own context being managed From a06216adf03409c2b400a601a6e2b722dddd73cd Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen Date: Mon, 25 Mar 2024 19:17:35 +0100 Subject: [PATCH 11/11] itest: Add test for neutrino sideload Signed-off-by: Ononiwu Maureen --- itest/lnd_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/itest/lnd_test.go b/itest/lnd_test.go index b5886bc299..ce7b3c1dbb 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -14,7 +14,9 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/integration/rpctest" + "github.com/lightninglabs/neutrino/sideload" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnrpc/chainrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/node" "github.com/lightningnetwork/lnd/lntest/port" @@ -102,6 +104,14 @@ func TestLightningNetworkDaemon(t *testing.T) { ) defer harnessTest.Stop() + if harnessTest.IsNeutrinoSideloadTest() { + t.Run("test neutrino sideload", func(t *testing.T) { + testNeutrinoSideload(t, harnessTest) + }) + + return + } + // Setup standby nodes, Alice and Bob, which will be alive and shared // among all the test cases. harnessTest.SetupStandbyNodes() @@ -156,6 +166,63 @@ func TestLightningNetworkDaemon(t *testing.T) { "cases, end height: %d\n", trancheIndex, len(testCases), height) } +func testNeutrinoSideload(t *testing.T, harness *lntest.HarnessTest) { + if !harness.IsNeutrinoSideloadTest() { + return + } + + testCfg := &sideload.TestCfg{ + StartHeight: 0, + EndHeight: 1000, + Net: harnessNetParams.Net, + DataType: sideload.BlockHeaders, + } + + headers := lntest.GenerateBlockHeaderBytes( + uint32(testCfg.EndHeight-testCfg.StartHeight), + harness.Miner.Harness, t, + ) + + reader := sideload.GenerateEncodedBinaryReader( + t, testCfg, headers, + ) + + tempFile, err := os.CreateTemp("", "neutrino") + require.NoError(t, err) + + defer func() { + err = tempFile.Close() + require.NoError(t, err) + + err = os.Remove(tempFile.Name()) + require.NoError(t, err) + }() + + _, err = io.Copy(tempFile, reader) + require.NoError(t, err) + + _, err = reader.Seek(0, io.SeekStart) + require.NoError(t, err) + + extraArgs := []string{ + "--neutrino.sideload.enable", + "--neutrino.sideload.sourceType=binary", + "--neutrino.sideload.sourcePath=" + tempFile.Name(), + "--neutrino.sideload.skipVerify", + } + + obiNode := harness.NewNode("obi", extraArgs) + d + + request := chainrpc.GetBlockHashRequest{ + BlockHeight: int64(testCfg.EndHeight), + } + + resp := obiNode.RPC.GetBlockHash(&request) + + require.NotZero(t, len(resp.BlockHash)) +} + // getTestCaseSplitTranche returns the sub slice of the test cases that should // be run as the current split tranche as well as the index and slice offset of // the tranche.