Repository: livepeer/go-livepeer (go)

Issue:
Nil Pointer in watchers while running in Arbitrum
```
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x58 pc=0x7ff75be2a3d5]

goroutine 32836 [running]:
github.com/livepeer/go-livepeer/eth/watchers.(*SenderWatcher).handleBlockEvents(0xc002c89fd0, {0xc000882100, 0x1c, 0x0})
        D:/a/go-livepeer/go-livepeer/eth/watchers/senderwatcher.go:152 +0x55
created by github.com/livepeer/go-livepeer/eth/watchers.(*SenderWatcher).Watch
        D:/a/go-livepeer/go-livepeer/eth/watchers/senderwatcher.go:116 +0x385
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x58 pc=0x7ff75be2c595]

goroutine 33 [running]:
github.com/livepeer/go-livepeer/eth/watchers.(*ServiceRegistryWatcher).handleBlockEvents(0xc000283f80, {0xc000882100, 0x1c, 0x0})
        D:/a/go-livepeer/go-livepeer/eth/watchers/serviceRegistryWatcher.go:61 +0x55
github.com/livepeer/go-livepeer/eth/watchers.(*ServiceRegistryWatcher).Watch(0xc000211e80)
        D:/a/go-livepeer/go-livepeer/eth/watchers/serviceRegistryWatcher.go:49 +0x20a
created by main.main
        D:/a/go-livepeer/go-livepeer/cmd/livepeer/livepeer.go:587 +0x43f8
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x58 pc=0x7ff75be2f355]

goroutine 32748 [running]:
github.com/livepeer/go-livepeer/eth/watchers.(*UnbondingWatcher).handleBlockEvents(0xc002c8ffd0, {0xc000882100, 0x1c, 0x0})
        D:/a/go-livepeer/go-livepeer/eth/watchers/unbondingwatcher.go:74 +0x55
created by github.com/livepeer/go-livepeer/eth/watchers.(*UnbondingWatcher).Watch
        D:/a/go-livepeer/go-livepeer/eth/watchers/unbondingwatcher.go:62 +0x2af
```

Pull request description:
Fix nil pointer in the block header logs
**What does this pull request do? Explain your changes. (required)**
Fixes a bug introduced in https://github.com/livepeer/go-livepeer/pull/2222, block header logs were not preserved while enriching block with L1 Number.

**Specific updates (required)**
<!--- List out all significant updates your code introduces -->
- 
- 
- 

**How did you test each of these updates (required)**
<!-- A detailed description of how you tested your code changes. Include details of your testing environment, and the tests you ran to see how your change affects other areas of the code, etc. -->

Unit test + checked in the debug that events returned from L2 API may not contain logs.


**Does this pull request close any open issues?**
<!-- Fixes # -->

fix #2265


**Checklist:**
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] Read the [contribution guide](./doc/contributing.md)
- [x] `make` runs successfully
- [x] All tests in `./test.sh` pass
- [ ] README and other documentation updated
- [ ] [Pending changelog](./CHANGELOG_PENDING.md) updated


Patch:
diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md
index 38d5e2ab..93f5cfe9 100644
--- a/CHANGELOG_PENDING.md
+++ b/CHANGELOG_PENDING.md
@@ -15,6 +15,7 @@
 #### Transcoder
 
 ### Bug Fixes 🐞
+- \#2267 Fix nil pointer in the block header logs (@leszko)
 
 #### General
 
@@ -22,4 +23,6 @@
 
 #### Orchestrator
 
+- \#2266 Fix default reward cut and fee cut in `livepeer_cli` (@leszko)
+
 #### Transcoder
diff --git a/cmd/livepeer/livepeer.go b/cmd/livepeer/livepeer.go
index 75d1d816..842d985e 100644
--- a/cmd/livepeer/livepeer.go
+++ b/cmd/livepeer/livepeer.go
@@ -94,7 +94,7 @@ func main() {
 	cliAddr := flag.String("cliAddr", "127.0.0.1:"+CliPort, "Address to bind for  CLI commands")
 	httpAddr := flag.String("httpAddr", "", "Address to bind for HTTP commands")
 	serviceAddr := flag.String("serviceAddr", "", "Orchestrator only. Overrides the on-chain serviceURI that broadcasters can use to contact this node; may be an IP or hostname.")
-	orchAddr := flag.String("orchAddr", "", "Orchestrator to connect to as a standalone transcoder")
+	orchAddr := flag.String("orchAddr", "", "Comma-separated list of orchestrators to connect to")
 	verifierURL := flag.String("verifierUrl", "", "URL of the verifier to use")
 
 	verifierPath := flag.String("verifierPath", "", "Path to verifier shared volume")
diff --git a/cmd/livepeer_cli/wizard_transcoder.go b/cmd/livepeer_cli/wizard_transcoder.go
index e07a551b..12c7b121 100644
--- a/cmd/livepeer_cli/wizard_transcoder.go
+++ b/cmd/livepeer_cli/wizard_transcoder.go
@@ -53,10 +53,10 @@ func (w *wizard) promptOrchestratorConfig() (float64, float64, int, int, string)
 	}
 
 	fmt.Printf("Enter block reward cut percentage (current=%v default=%v) - ", blockRewardCut, defaultRewardCut)
-	blockRewardCut = w.readDefaultFloat(blockRewardCut)
+	blockRewardCut = w.readDefaultFloat(defaultRewardCut)
 
 	fmt.Printf("Enter fee cut percentage (current=%v default=%v) - ", feeCut, defaultFeeCut)
-	feeCut = w.readDefaultFloat(feeCut)
+	feeCut = w.readDefaultFloat(defaultFeeCut)
 
 	fmt.Println("Enter a transcoding base price in wei per pixels")
 	fmt.Println("eg. 1 wei / 10 pixels = 0,1 wei per pixel")
diff --git a/core/capabilities.go b/core/capabilities.go
index 9c3c87b4..150752d8 100644
--- a/core/capabilities.go
+++ b/core/capabilities.go
@@ -48,6 +48,32 @@ const (
 	Capability_VP9_Encode
 )
 
+var CapabilityNameLookup = map[Capability]string {
+	Capability_Invalid: "Invalid",
+	Capability_Unused: "Unused",
+	Capability_H264: "H.264",
+	Capability_MPEGTS: "MPEGTS",
+	Capability_MP4: "MP4",
+	Capability_FractionalFramerates: "Fractional framerates",
+	Capability_StorageDirect: "Storage direct",
+	Capability_StorageS3: "Storage S3",
+	Capability_StorageGCS: "Storage GCS",
+	Capability_ProfileH264Baseline: "H264 Baseline profile",
+	Capability_ProfileH264Main: "H264 Main profile",
+	Capability_ProfileH264High: "H264 High profile",
+	Capability_ProfileH264ConstrainedHigh: "H264 Constained High profile",
+	Capability_GOP: "GOP",
+	Capability_AuthToken: "Auth token",
+	Capability_SceneClassification: "Scene slassification",
+	Capability_MPEG7VideoSignature: "MPEG7 signature",
+	Capability_HEVC_Decode: "HEVC decode",
+	Capability_HEVC_Encode: "HEVC encode",
+	Capability_VP8_Decode: "VP8 decode",
+	Capability_VP9_Decode: "VP9 decode",
+	Capability_VP8_Encode: "VP8 encode",
+	Capability_VP9_Encode: "VP9 encode",
+}
+
 
 var CapabilityTestLookup = map[Capability]CapabilityTest{
 	// 145x145 is the lowest resolution supported by NVENC on Windows
@@ -77,6 +103,7 @@ var capFormatConv = errors.New("capability: unknown format")
 var capStorageConv = errors.New("capability: unknown storage")
 var capProfileConv = errors.New("capability: unknown profile")
 var capCodecConv = errors.New("capability: unknown codec")
+var capUnknown = errors.New("capability: unknown")
 
 func DefaultCapabilities() []Capability {
 	// Add to this list as new features are added.
@@ -279,6 +306,23 @@ func NewCapabilities(caps []Capability, m []Capability) *Capabilities {
 	return c
 }
 
+func CapabilityToName(capability Capability) (string, error) {
+	capName, found := CapabilityNameLookup[capability]
+	if !found {
+		return "", capUnknown
+	}
+	return capName, nil
+}
+
+func InArray(capability Capability, caps []Capability) bool {
+	for _, c := range caps {
+		if capability == c {
+			return true
+		}
+	}
+	return false
+}
+
 func inputCodecToCapability(codec ffmpeg.VideoCodec) (Capability, error) {
 	switch codec {
 	case ffmpeg.H264:
diff --git a/core/transcoder.go b/core/transcoder.go
index b381b5fb..9842837d 100644
--- a/core/transcoder.go
+++ b/core/transcoder.go
@@ -119,9 +119,18 @@ func (nv *NvidiaTranscoder) Transcode(ctx context.Context, md *SegTranscodingMet
 func TestTranscoderCapabilities(devices []string) (caps []Capability, fatalError error) {
 	// default capabilities
 	allCaps := append(DefaultCapabilities(), OptionalCapabilities()...)
+	fname := filepath.Join(WorkDir, "testseg.tempfile")
+	defer os.Remove(fname)
+	nvTest3Rend := true
 	// iterate all capabilities and test ones which has test data
 	for _, c := range allCaps {
 		capTest, hasTest := CapabilityTestLookup[c]
+		capName, _ := CapabilityToName(c)
+		isRequired := InArray(c, DefaultCapabilities())
+		capKindStr := "Optional capability"
+		if isRequired {
+			capKindStr = "Required capability"
+		}
 		if hasTest {
 			b := bytes.NewReader(capTest.inVideoData)
 			z, err := gzip.NewReader(b)
@@ -134,13 +143,11 @@ func TestTranscoderCapabilities(devices []string) (caps []Capability, fatalError
 				glog.Errorf("Error reading test segment for capability %d: %s", c, err)
 				continue
 			}
-			fname := filepath.Join(WorkDir, "testseg.tempfile")
 			err = ioutil.WriteFile(fname, mp4testSeg, 0644)
 			if err != nil {
 				glog.Errorf("Error writing test segment for capability %d: %s", c, err)
 				continue
 			}
-			defer os.Remove(fname)
 			// check that capability is supported on all devices
 			for _, device := range devices {
 				t1 := NewNvidiaTranscoder(device)
@@ -149,29 +156,36 @@ func TestTranscoderCapabilities(devices []string) (caps []Capability, fatalError
 				td, err := t1.Transcode(context.Background(), md)
 				t1.Stop()
 				if err != nil {
-					// likely means capability is not supported
+					glog.Infof("%s %q is not supported on device %s, see other error messages for details", capKindStr, capName, device)
+					// likely means capability is not supported, don't check on other devices
 					goto test_fail
 				}
 				if len(td.Segments) == 0 || td.Pixels == 0 {
 					// abnormal behavior
-					glog.Errorf("Empty result segment when testing for capability %d", c)
+					glog.Errorf("Empty result segment when testing for %s %q", strings.ToLower(capKindStr), capName)
 					goto test_fail
 				}
+				// no error creating 4 renditions - disable 3 renditions test, as restriction is on driver level, not device
+				nvTest3Rend = false
 			}
 		}
 		caps = append(caps, c)
-		test_fail:
-	}
-	for _, defCap := range DefaultCapabilities() {
-		found := false
-		for _, supportedCap := range caps {
-			if defCap == supportedCap {
-				found = true
-				break
+		continue
+	test_fail:
+		if nvTest3Rend {
+			// if 4 renditions didn't succeed, try 3 renditions on first device to check if it could be session limit
+			t1 := NewNvidiaTranscoder(devices[0])
+			md := &SegTranscodingMetadata{Fname: fname, Profiles: []ffmpeg.VideoProfile{capTest.outProfile, capTest.outProfile, capTest.outProfile}}
+			td, err := t1.Transcode(context.Background(), md)
+			t1.Stop()
+			if err == nil && len(td.Segments) > 0 && td.Pixels > 0 {
+				glog.Error("Maximum number of simultaneous NVENC video encoding sessions is restricted by driver")
 			}
+			// do it only once
+			nvTest3Rend = false
 		}
-		if !found {
-			return caps, fmt.Errorf("Default capability %d is not supported", defCap)
+		if isRequired {
+			return nil, fmt.Errorf("%s %q is not supported on hardware", capKindStr, capName)
 		}
 	}
 	return caps, nil
diff --git a/eth/blockwatch/block_watcher.go b/eth/blockwatch/block_watcher.go
index 084676ec..c097b580 100644
--- a/eth/blockwatch/block_watcher.go
+++ b/eth/blockwatch/block_watcher.go
@@ -637,7 +637,12 @@ func (w *Watcher) enrichWithL1BlockNumber(header *MiniHeader) (*MiniHeader, erro
 	if header == nil || header.L1BlockNumber != nil {
 		return header, nil
 	}
-	return w.client.HeaderByHash(header.Hash)
+	fetchedBlock, err := w.client.HeaderByHash(header.Hash)
+	if err != nil {
+		return header, err
+	}
+	header.L1BlockNumber = fetchedBlock.L1BlockNumber
+	return header, nil
 }
 
 func isUnknownBlockErr(err error) bool {


Test patch:
diff --git a/eth/blockwatch/block_watcher_test.go b/eth/blockwatch/block_watcher_test.go
index 7fc05df1..f94f68b4 100644
--- a/eth/blockwatch/block_watcher_test.go
+++ b/eth/blockwatch/block_watcher_test.go
@@ -527,6 +527,7 @@ func TestEnrichWithL1_One(t *testing.T) {
 	header := &MiniHeader{
 		Number: big.NewInt(FakeBlockNumber),
 		Hash:   common.HexToHash(FakeHash),
+		Logs:   []types.Log{logStub},
 	}
 	events := []*Event{{BlockHeader: header}}
 
@@ -536,6 +537,7 @@ func TestEnrichWithL1_One(t *testing.T) {
 	assert.Equal(common.HexToHash(FakeHash), res[0].BlockHeader.Hash)
 	assert.Equal(big.NewInt(FakeBlockNumber), res[0].BlockHeader.Number)
 	assert.Equal(big.NewInt(FakeL1BlockNumber), res[0].BlockHeader.L1BlockNumber)
+	assert.Contains(res[0].BlockHeader.Logs, logStub)
 }
 
 func TestEnrichWithL1_Multiple(t *testing.T) {