From ef9e90c23a68424c5e25cfb85377bcfb05fea326 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Tue, 12 Nov 2024 11:19:18 +0100 Subject: [PATCH 1/4] Make golangci-lint 1.62.0 happy The linter learned how to find missing checks for safe typecasts and we had some spots where they weren't being checked. --- arbnode/delayed.go | 6 +++++- arbnode/sequencer_inbox.go | 6 +++++- broadcastclient/broadcastclient_test.go | 21 ++++++++++++++++++--- broadcaster/backlog/backlog.go | 2 +- cmd/genericconf/filehandler_test.go | 6 +++++- das/reader_aggregator_strategies_test.go | 6 ++++-- execution/nodeInterface/NodeInterface.go | 12 ++++++++++-- linters/koanf/handlers.go | 6 +++++- system_tests/seq_coordinator_test.go | 13 ++++++++++--- system_tests/seq_reject_test.go | 4 ++-- system_tests/seqfeed_test.go | 13 ++++++------- util/containers/syncmap.go | 13 +++++++++++-- util/testhelpers/port.go | 11 +++++++++++ util/testhelpers/port_test.go | 12 ++++++++++-- 14 files changed, 103 insertions(+), 28 deletions(-) diff --git a/arbnode/delayed.go b/arbnode/delayed.go index 354fa671b3..f28a9617a3 100644 --- a/arbnode/delayed.go +++ b/arbnode/delayed.go @@ -334,7 +334,11 @@ func (b *DelayedBridge) parseMessage(ctx context.Context, ethLog types.Log) (*bi if err != nil { return nil, nil, err } - return parsedLog.MessageNum, args["messageData"].([]byte), nil + dataBytes, ok := args["messageData"].([]byte) + if !ok { + return nil, nil, errors.New("messageData not a byte array") + } + return parsedLog.MessageNum, dataBytes, nil default: return nil, nil, errors.New("unexpected log type") } diff --git a/arbnode/sequencer_inbox.go b/arbnode/sequencer_inbox.go index 81146ed46e..b2840492fe 100644 --- a/arbnode/sequencer_inbox.go +++ b/arbnode/sequencer_inbox.go @@ -124,7 +124,11 @@ func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client *ethc if err != nil { return nil, err } - return args["data"].([]byte), nil + dataBytes, ok := args["data"].([]byte) + if !ok { + return nil, errors.New("args[\"data\"] not a byte array") + } + return dataBytes, nil case batchDataSeparateEvent: var numberAsHash common.Hash binary.BigEndian.PutUint64(numberAsHash[(32-8):], m.SequenceNumber) diff --git a/broadcastclient/broadcastclient_test.go b/broadcastclient/broadcastclient_test.go index a499628cd5..d9f7443af5 100644 --- a/broadcastclient/broadcastclient_test.go +++ b/broadcastclient/broadcastclient_test.go @@ -138,7 +138,11 @@ func TestInvalidSignature(t *testing.T) { badPrivateKey, err := crypto.GenerateKey() Require(t, err) badPublicKey := badPrivateKey.Public() - badSequencerAddr := crypto.PubkeyToAddress(*badPublicKey.(*ecdsa.PublicKey)) + badECDSA, ok := badPublicKey.(*ecdsa.PublicKey) + if !ok { + t.Fatal("badPublicKey is not an ecdsa.PublicKey") + } + badSequencerAddr := crypto.PubkeyToAddress(*badECDSA) config := DefaultTestConfig ts := NewDummyTransactionStreamer(chainId, &badSequencerAddr) @@ -151,6 +155,7 @@ func TestInvalidSignature(t *testing.T) { nil, fatalErrChan, &badSequencerAddr, + t, ) Require(t, err) broadcastClient.Start(ctx) @@ -201,8 +206,9 @@ func (ts *dummyTransactionStreamer) AddBroadcastMessages(feedMessages []*m.Broad return nil } -func newTestBroadcastClient(config Config, listenerAddress net.Addr, chainId uint64, currentMessageCount arbutil.MessageIndex, txStreamer TransactionStreamerInterface, confirmedSequenceNumberListener chan arbutil.MessageIndex, feedErrChan chan error, validAddr *common.Address) (*BroadcastClient, error) { - port := listenerAddress.(*net.TCPAddr).Port +func newTestBroadcastClient(config Config, listenerAddress net.Addr, chainId uint64, currentMessageCount arbutil.MessageIndex, txStreamer TransactionStreamerInterface, confirmedSequenceNumberListener chan arbutil.MessageIndex, feedErrChan chan error, validAddr *common.Address, t *testing.T) (*BroadcastClient, error) { + t.Helper() + port := testhelpers.AddrTCPPort(listenerAddress, t) var av contracts.AddressVerifierInterface if validAddr != nil { config.Verify.AcceptSequencer = true @@ -225,6 +231,7 @@ func startMakeBroadcastClient(ctx context.Context, t *testing.T, clientConfig Co nil, feedErrChan, sequencerAddr, + t, ) Require(t, err) broadcastClient.Start(ctx) @@ -313,6 +320,7 @@ func TestServerClientDisconnect(t *testing.T) { nil, feedErrChan, &sequencerAddr, + t, ) Require(t, err) broadcastClient.Start(ctx) @@ -384,6 +392,7 @@ func TestBroadcastClientConfirmedMessage(t *testing.T) { confirmedSequenceNumberListener, feedErrChan, &sequencerAddr, + t, ) Require(t, err) broadcastClient.Start(ctx) @@ -456,6 +465,7 @@ func TestServerIncorrectChainId(t *testing.T) { nil, badFeedErrChan, &sequencerAddr, + t, ) Require(t, err) badBroadcastClient.Start(ctx) @@ -515,6 +525,7 @@ func TestServerMissingChainId(t *testing.T) { nil, badFeedErrChan, &sequencerAddr, + t, ) Require(t, err) badBroadcastClient.Start(ctx) @@ -572,6 +583,7 @@ func TestServerIncorrectFeedServerVersion(t *testing.T) { nil, badFeedErrChan, &sequencerAddr, + t, ) Require(t, err) badBroadcastClient.Start(ctx) @@ -631,6 +643,7 @@ func TestServerMissingFeedServerVersion(t *testing.T) { nil, badFeedErrChan, &sequencerAddr, + t, ) Require(t, err) badBroadcastClient.Start(ctx) @@ -682,6 +695,7 @@ func TestBroadcastClientReconnectsOnServerDisconnect(t *testing.T) { nil, feedErrChan, &sequencerAddr, + t, ) Require(t, err) broadcastClient.Start(ctx) @@ -794,6 +808,7 @@ func connectAndGetCachedMessages(ctx context.Context, addr net.Addr, chainId uin nil, feedErrChan, sequencerAddr, + t, ) Require(t, err) broadcastClient.Start(ctx) diff --git a/broadcaster/backlog/backlog.go b/broadcaster/backlog/backlog.go index b7b935fb7a..413a14b782 100644 --- a/broadcaster/backlog/backlog.go +++ b/broadcaster/backlog/backlog.go @@ -328,7 +328,7 @@ func newBacklogSegment() *backlogSegment { func IsBacklogSegmentNil(segment BacklogSegment) bool { if segment == nil { return true - } else if segment.(*backlogSegment) == nil { + } else if bs, ok := segment.(*backlogSegment); ok && bs == nil { return true } return false diff --git a/cmd/genericconf/filehandler_test.go b/cmd/genericconf/filehandler_test.go index daa9ed397c..adf468bc1d 100644 --- a/cmd/genericconf/filehandler_test.go +++ b/cmd/genericconf/filehandler_test.go @@ -55,7 +55,11 @@ func readLogMessagesFromJSONFile(t *testing.T, path string) ([]string, error) { if !ok { testhelpers.FailImpl(t, "Incorrect record, msg key is missing", "record", record) } - messages = append(messages, msg.(string)) + msgString, ok := msg.(string) + if !ok { + testhelpers.FailImpl(t, "Incorrect record, msg is not a string", "record", record) + } + messages = append(messages, msgString) } if errors.Is(err, io.EOF) { return messages, nil diff --git a/das/reader_aggregator_strategies_test.go b/das/reader_aggregator_strategies_test.go index cdb85b25e9..67d8681f78 100644 --- a/das/reader_aggregator_strategies_test.go +++ b/das/reader_aggregator_strategies_test.go @@ -72,8 +72,10 @@ func TestDAS_SimpleExploreExploit(t *testing.T) { } for i := 0; i < len(was) && doMatch; i++ { - if expected[i].(*dummyReader).int != was[i].(*dummyReader).int { - Fail(t, fmt.Sprintf("expected %d, was %d", expected[i].(*dummyReader).int, was[i].(*dummyReader).int)) + expR, expOK := expected[i].(*dummyReader) + wasR, wasOK := was[i].(*dummyReader) + if !expOK || !wasOK || expR.int != wasR.int { + Fail(t, fmt.Sprintf("expected %d, was %d", expected[i], was[i])) } } } diff --git a/execution/nodeInterface/NodeInterface.go b/execution/nodeInterface/NodeInterface.go index 00da1ba4b6..cd87e23b73 100644 --- a/execution/nodeInterface/NodeInterface.go +++ b/execution/nodeInterface/NodeInterface.go @@ -525,7 +525,11 @@ func (n NodeInterface) GasEstimateL1Component( if err := args.CallDefaults(randomGas, evm.Context.BaseFee, evm.ChainConfig().ChainID); err != nil { return 0, nil, nil, err } - msg := args.ToMessage(evm.Context.BaseFee, randomGas, n.header, evm.StateDB.(*state.StateDB), core.MessageEthcallMode) + sdb, ok := evm.StateDB.(*state.StateDB) + if !ok { + return 0, nil, nil, errors.New("failed to cast to stateDB") + } + msg := args.ToMessage(evm.Context.BaseFee, randomGas, n.header, sdb, core.MessageEthcallMode) pricing := c.State.L1PricingState() l1BaseFeeEstimate, err := pricing.PricePerUnit() @@ -581,7 +585,11 @@ func (n NodeInterface) GasEstimateComponents( if err := args.CallDefaults(gasCap, evm.Context.BaseFee, evm.ChainConfig().ChainID); err != nil { return 0, 0, nil, nil, err } - msg := args.ToMessage(evm.Context.BaseFee, gasCap, n.header, evm.StateDB.(*state.StateDB), core.MessageGasEstimationMode) + sdb, ok := evm.StateDB.(*state.StateDB) + if !ok { + return 0, 0, nil, nil, errors.New("failed to cast to stateDB") + } + msg := args.ToMessage(evm.Context.BaseFee, gasCap, n.header, sdb, core.MessageGasEstimationMode) brotliCompressionLevel, err := c.State.BrotliCompressionLevel() if err != nil { return 0, 0, nil, nil, fmt.Errorf("failed to get brotli compression level: %w", err) diff --git a/linters/koanf/handlers.go b/linters/koanf/handlers.go index 5ee3b80f9f..e3f7c67f68 100644 --- a/linters/koanf/handlers.go +++ b/linters/koanf/handlers.go @@ -126,7 +126,11 @@ func checkFlagDefs(pass *analysis.Pass, f *ast.FuncDecl, cnt map[string]int) Res if !ok { continue } - handleSelector(pass, callE.Args[1].(*ast.SelectorExpr), -1, cnt) + sel, ok := callE.Args[1].(*ast.SelectorExpr) + if !ok { + continue + } + handleSelector(pass, sel, -1, cnt) if normSL := normalizeTag(sl); !strings.EqualFold(normSL, s) { res.Errors = append(res.Errors, koanfError{ Pos: f.Pos(), diff --git a/system_tests/seq_coordinator_test.go b/system_tests/seq_coordinator_test.go index e7d8bf6b39..76cff95f04 100644 --- a/system_tests/seq_coordinator_test.go +++ b/system_tests/seq_coordinator_test.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "math/big" - "net" "testing" "time" @@ -153,7 +152,15 @@ func TestRedisSeqCoordinatorPriorities(t *testing.T) { nodeForwardTarget := func(nodeNum int) int { execNode := testNodes[nodeNum].ExecNode - fwTarget := execNode.TxPublisher.(*gethexec.TxPreChecker).TransactionPublisher.(*gethexec.Sequencer).ForwardTarget() + preChecker, ok := execNode.TxPublisher.(*gethexec.TxPreChecker) + if !ok { + return -1 + } + sequencer, ok := preChecker.TransactionPublisher.(*gethexec.Sequencer) + if !ok { + return -1 + } + fwTarget := sequencer.ForwardTarget() if fwTarget == "" { return -1 } @@ -323,7 +330,7 @@ func testCoordinatorMessageSync(t *testing.T, successCase bool) { // nodeB doesn't sequence transactions, but adds messages related to them to its output feed. // nodeBOutputFeedReader reads those messages from this feed and processes them. // nodeBOutputFeedReader doesn't read messages from L1 since none of the nodes posts to L1. - nodeBPort := testClientB.ConsensusNode.BroadcastServer.ListenerAddr().(*net.TCPAddr).Port + nodeBPort := testhelpers.AddrTCPPort(testClientB.ConsensusNode.BroadcastServer.ListenerAddr(), t) nodeConfigNodeBOutputFeedReader := arbnode.ConfigDefaultL1NonSequencerTest() nodeConfigNodeBOutputFeedReader.Feed.Input = *newBroadcastClientConfigTest(nodeBPort) testClientNodeBOutputFeedReader, cleanupNodeBOutputFeedReader := builder.Build2ndNode(t, &SecondNodeParams{nodeConfig: nodeConfigNodeBOutputFeedReader}) diff --git a/system_tests/seq_reject_test.go b/system_tests/seq_reject_test.go index 2dbdba6804..fa2d1c382d 100644 --- a/system_tests/seq_reject_test.go +++ b/system_tests/seq_reject_test.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "math/big" - "net" "strings" "sync" "sync/atomic" @@ -20,6 +19,7 @@ import ( "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/colors" + "github.com/offchainlabs/nitro/util/testhelpers" ) func TestSequencerRejection(t *testing.T) { @@ -35,7 +35,7 @@ func TestSequencerRejection(t *testing.T) { builder := NewNodeBuilder(ctx).DefaultConfig(t, false) builder.takeOwnership = false - port := builderSeq.L2.ConsensusNode.BroadcastServer.ListenerAddr().(*net.TCPAddr).Port + port := testhelpers.AddrTCPPort(builderSeq.L2.ConsensusNode.BroadcastServer.ListenerAddr(), t) builder.nodeConfig.Feed.Input = *newBroadcastClientConfigTest(port) cleanup := builder.Build(t) defer cleanup() diff --git a/system_tests/seqfeed_test.go b/system_tests/seqfeed_test.go index 21f0755225..a5180b5773 100644 --- a/system_tests/seqfeed_test.go +++ b/system_tests/seqfeed_test.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "math/big" - "net" "reflect" "testing" "time" @@ -61,7 +60,7 @@ func TestSequencerFeed(t *testing.T) { defer cleanupSeq() seqInfo, seqNode, seqClient := builderSeq.L2Info, builderSeq.L2.ConsensusNode, builderSeq.L2.Client - port := seqNode.BroadcastServer.ListenerAddr().(*net.TCPAddr).Port + port := testhelpers.AddrTCPPort(seqNode.BroadcastServer.ListenerAddr(), t) builder := NewNodeBuilder(ctx).DefaultConfig(t, false) builder.nodeConfig.Feed.Input = *newBroadcastClientConfigTest(port) builder.takeOwnership = false @@ -107,7 +106,7 @@ func TestRelayedSequencerFeed(t *testing.T) { Require(t, err) config := relay.ConfigDefault - port := seqNode.BroadcastServer.ListenerAddr().(*net.TCPAddr).Port + port := testhelpers.AddrTCPPort(seqNode.BroadcastServer.ListenerAddr(), t) config.Node.Feed.Input = *newBroadcastClientConfigTest(port) config.Node.Feed.Output = *newBroadcasterConfigTest() config.Chain.ID = bigChainId.Uint64() @@ -119,7 +118,7 @@ func TestRelayedSequencerFeed(t *testing.T) { Require(t, err) defer currentRelay.StopAndWait() - port = currentRelay.GetListenerAddr().(*net.TCPAddr).Port + port = testhelpers.AddrTCPPort(currentRelay.GetListenerAddr(), t) builder := NewNodeBuilder(ctx).DefaultConfig(t, false) builder.nodeConfig.Feed.Input = *newBroadcastClientConfigTest(port) builder.takeOwnership = false @@ -219,7 +218,7 @@ func testLyingSequencer(t *testing.T, dasModeStr string) { defer cleanupC() l2clientC, nodeC := testClientC.Client, testClientC.ConsensusNode - port := nodeC.BroadcastServer.ListenerAddr().(*net.TCPAddr).Port + port := testhelpers.AddrTCPPort(nodeC.BroadcastServer.ListenerAddr(), t) // The client node, connects to lying sequencer's feed nodeConfigB := arbnode.ConfigDefaultL1NonSequencerTest() @@ -361,7 +360,7 @@ func testBlockHashComparison(t *testing.T, blockHash *common.Hash, mustMismatch } defer wsBroadcastServer.StopAndWait() - port := wsBroadcastServer.ListenerAddr().(*net.TCPAddr).Port + port := testhelpers.AddrTCPPort(wsBroadcastServer.ListenerAddr(), t) builder := NewNodeBuilder(ctx).DefaultConfig(t, true) builder.nodeConfig.Feed.Input = *newBroadcastClientConfigTest(port) @@ -468,7 +467,7 @@ func TestPopulateFeedBacklog(t *testing.T) { // Creates a sink node that will read from the output feed of the previous node. nodeConfigSink := builder.nodeConfig - port := builder.L2.ConsensusNode.BroadcastServer.ListenerAddr().(*net.TCPAddr).Port + port := testhelpers.AddrTCPPort(builder.L2.ConsensusNode.BroadcastServer.ListenerAddr(), t) nodeConfigSink.Feed.Input = *newBroadcastClientConfigTest(port) testClientSink, cleanupSink := builder.Build2ndNode(t, &SecondNodeParams{nodeConfig: nodeConfigSink}) defer cleanupSink() diff --git a/util/containers/syncmap.go b/util/containers/syncmap.go index e24d56fda6..cc7563faec 100644 --- a/util/containers/syncmap.go +++ b/util/containers/syncmap.go @@ -12,7 +12,12 @@ func (m *SyncMap[K, V]) Load(key K) (V, bool) { var empty V return empty, false } - return val.(V), true + vVal, ok := val.(V) + if !ok { + var empty V + return empty, false + } + return vVal, true } func (m *SyncMap[K, V]) Store(key K, val V) { @@ -27,7 +32,11 @@ func (m *SyncMap[K, V]) Delete(key K) { func (m *SyncMap[K, V]) Keys() []K { s := make([]K, 0) m.internal.Range(func(k, v interface{}) bool { - s = append(s, k.(K)) + kKey, ok := k.(K) + if !ok { + return false + } + s = append(s, kKey) return true }) return s diff --git a/util/testhelpers/port.go b/util/testhelpers/port.go index d31fa41cdc..c17e9d9ec2 100644 --- a/util/testhelpers/port.go +++ b/util/testhelpers/port.go @@ -2,6 +2,7 @@ package testhelpers import ( "net" + "testing" ) // FreeTCPPortListener returns a listener listening on an unused local port. @@ -15,3 +16,13 @@ func FreeTCPPortListener() (net.Listener, error) { } return l, nil } + +// Func AddrTCPPort returns the port of a net.Addr. +func AddrTCPPort(n net.Addr, t *testing.T) int { + t.Helper() + tcpAddr, ok := n.(*net.TCPAddr) + if !ok { + t.Fatal("Could not get TCP address net.Addr") + } + return tcpAddr.Port +} diff --git a/util/testhelpers/port_test.go b/util/testhelpers/port_test.go index ef9bb18537..bb8f87b2f7 100644 --- a/util/testhelpers/port_test.go +++ b/util/testhelpers/port_test.go @@ -14,10 +14,18 @@ func TestFreeTCPPortListener(t *testing.T) { if err != nil { t.Fatal(err) } - if aListener.Addr().(*net.TCPAddr).Port == bListener.Addr().(*net.TCPAddr).Port { + aTCPAddr, ok := aListener.Addr().(*net.TCPAddr) + if !ok { + t.Fatalf("aListener.Addr() is not a *net.TCPAddr: %v", aListener.Addr()) + } + bTCPAddr, ok := bListener.Addr().(*net.TCPAddr) + if !ok { + t.Fatalf("bListener.Addr() is not a *net.TCPAddr: %v", aListener.Addr()) + } + if aTCPAddr.Port == bTCPAddr.Port { t.Errorf("FreeTCPPortListener() got same port: %v, %v", aListener, bListener) } - if aListener.Addr().(*net.TCPAddr).Port == 0 || bListener.Addr().(*net.TCPAddr).Port == 0 { + if aTCPAddr.Port == 0 || bTCPAddr.Port == 0 { t.Errorf("FreeTCPPortListener() got port 0") } } From 8e039e0ddde81e4145c551c6c4698e7faa16f4d8 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Tue, 12 Nov 2024 14:28:32 +0100 Subject: [PATCH 2/4] Also log an error if the backlogSegment type cannot be asserted --- broadcaster/backlog/backlog.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/broadcaster/backlog/backlog.go b/broadcaster/backlog/backlog.go index 413a14b782..d75e5dafe5 100644 --- a/broadcaster/backlog/backlog.go +++ b/broadcaster/backlog/backlog.go @@ -328,7 +328,13 @@ func newBacklogSegment() *backlogSegment { func IsBacklogSegmentNil(segment BacklogSegment) bool { if segment == nil { return true - } else if bs, ok := segment.(*backlogSegment); ok && bs == nil { + } + bs, ok := segment.(*backlogSegment) + if !ok { + log.Error("error in backlogSegment type assertion: clearing backlog") + return false + } + if bs == nil { return true } return false From b51dcfdd71cb33b3070490a8bffea84c340b0a89 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Tue, 12 Nov 2024 16:27:48 +0100 Subject: [PATCH 3/4] Panic in syncmap if the key cannot be converted to the type --- util/containers/syncmap.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/containers/syncmap.go b/util/containers/syncmap.go index cc7563faec..da15afaacc 100644 --- a/util/containers/syncmap.go +++ b/util/containers/syncmap.go @@ -1,6 +1,9 @@ package containers -import "sync" +import ( + "fmt" + "sync" +) type SyncMap[K any, V any] struct { internal sync.Map @@ -34,7 +37,7 @@ func (m *SyncMap[K, V]) Keys() []K { m.internal.Range(func(k, v interface{}) bool { kKey, ok := k.(K) if !ok { - return false + panic(fmt.Sprintf("type assertion failed on %s", k)) } s = append(s, kKey) return true From 86b6cf0e94f388c38dd704167ae0a925d3bfc855 Mon Sep 17 00:00:00 2001 From: Pepper Lebeck-Jobe Date: Tue, 12 Nov 2024 16:46:20 +0100 Subject: [PATCH 4/4] Also panic in the other syncmap function on failed type assertions --- util/containers/syncmap.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/containers/syncmap.go b/util/containers/syncmap.go index da15afaacc..9190d81974 100644 --- a/util/containers/syncmap.go +++ b/util/containers/syncmap.go @@ -17,8 +17,7 @@ func (m *SyncMap[K, V]) Load(key K) (V, bool) { } vVal, ok := val.(V) if !ok { - var empty V - return empty, false + panic(fmt.Sprintf("type assertion failed on %s", val)) } return vVal, true }