Skip to content

Commit 14f4d96

Browse files
authored
Merge branch 'master' into NIT-3501
2 parents 601d818 + 2b3cf21 commit 14f4d96

File tree

6 files changed

+92
-45
lines changed

6 files changed

+92
-45
lines changed

arbos/arbostypes/messagewithmeta.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,10 @@ package arbostypes
22

33
import (
44
"context"
5-
"encoding/binary"
6-
"fmt"
75

86
"github.com/ethereum/go-ethereum/common"
9-
"github.com/ethereum/go-ethereum/crypto"
10-
"github.com/ethereum/go-ethereum/rlp"
11-
12-
"github.com/offchainlabs/nitro/arbutil"
137
)
148

15-
var uniquifyingPrefix = []byte("Arbitrum Nitro Feed:")
16-
179
type MessageWithMetadata struct {
1810
Message *L1IncomingMessage `json:"message"`
1911
DelayedMessagesRead uint64 `json:"delayedMessagesRead"`
@@ -35,20 +27,6 @@ var TestMessageWithMetadataAndRequestId = MessageWithMetadata{
3527
Message: &TestIncomingMessageWithRequestId,
3628
}
3729

38-
func (m *MessageWithMetadata) Hash(sequenceNumber arbutil.MessageIndex, chainId uint64) (common.Hash, error) {
39-
serializedExtraData := make([]byte, 24)
40-
binary.BigEndian.PutUint64(serializedExtraData[:8], uint64(sequenceNumber))
41-
binary.BigEndian.PutUint64(serializedExtraData[8:16], chainId)
42-
binary.BigEndian.PutUint64(serializedExtraData[16:], m.DelayedMessagesRead)
43-
44-
serializedMessage, err := rlp.EncodeToBytes(m.Message)
45-
if err != nil {
46-
return common.Hash{}, fmt.Errorf("unable to serialize message %v: %w", sequenceNumber, err)
47-
}
48-
49-
return crypto.Keccak256Hash(uniquifyingPrefix, serializedExtraData, serializedMessage), nil
50-
}
51-
5230
type InboxMultiplexer interface {
5331
Pop(context.Context) (*MessageWithMetadata, error)
5432
DelayedMessagesRead() uint64

broadcastclient/broadcastclient.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,9 +563,6 @@ func (bc *BroadcastClient) isValidSignature(ctx context.Context, message *messag
563563
// Verifier disabled
564564
return nil
565565
}
566-
hash, err := message.Hash(bc.chainId)
567-
if err != nil {
568-
return fmt.Errorf("error getting message hash for sequence number %v: %w", message.SequenceNumber, err)
569-
}
566+
hash := message.SignatureHash(bc.chainId)
570567
return bc.sigVerifier.VerifyHash(ctx, message.Signature, hash)
571568
}

broadcaster/broadcaster.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,22 @@ func (b *Broadcaster) NewBroadcastFeedMessage(
4545
blockHash *common.Hash,
4646
blockMetadata common.BlockMetadata,
4747
) (*m.BroadcastFeedMessage, error) {
48-
var messageSignature []byte
48+
feedMessage := m.BroadcastFeedMessage{
49+
SequenceNumber: sequenceNumber,
50+
Message: message,
51+
BlockHash: blockHash,
52+
Signature: []byte{},
53+
BlockMetadata: blockMetadata,
54+
}
4955
if b.dataSigner != nil {
50-
hash, err := message.Hash(sequenceNumber, b.chainId)
51-
if err != nil {
52-
return nil, err
53-
}
54-
messageSignature, err = b.dataSigner(hash.Bytes())
56+
hash := feedMessage.SignatureHash(b.chainId)
57+
var err error
58+
feedMessage.Signature, err = b.dataSigner(hash.Bytes())
5559
if err != nil {
5660
return nil, err
5761
}
5862
}
59-
60-
return &m.BroadcastFeedMessage{
61-
SequenceNumber: sequenceNumber,
62-
Message: message,
63-
BlockHash: blockHash,
64-
Signature: messageSignature,
65-
BlockMetadata: blockMetadata,
66-
}, nil
63+
return &feedMessage, nil
6764
}
6865

6966
func (b *Broadcaster) BroadcastSingle(

broadcaster/message/message.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package message
22

33
import (
4+
"encoding/binary"
5+
46
"github.com/ethereum/go-ethereum/common"
7+
"github.com/ethereum/go-ethereum/crypto"
58

69
"github.com/offchainlabs/nitro/arbos/arbostypes"
710
"github.com/offchainlabs/nitro/arbutil"
@@ -12,6 +15,8 @@ const (
1215
TimeboostedVersion = byte(0)
1316
)
1417

18+
var uniquifyingPrefix = []byte("Arbitrum Nitro Feed:")
19+
1520
// BroadcastMessage is the base message type for messages to send over the network.
1621
//
1722
// Acts as a variant holding the message types. The type of the message is
@@ -37,7 +42,7 @@ type BroadcastFeedMessage struct {
3742
SequenceNumber arbutil.MessageIndex `json:"sequenceNumber"`
3843
Message arbostypes.MessageWithMetadata `json:"message"`
3944
BlockHash *common.Hash `json:"blockHash,omitempty"`
40-
Signature []byte `json:"signature"`
45+
Signature []byte `json:"signatureV2"`
4146
BlockMetadata common.BlockMetadata `json:"blockMetadata,omitempty"`
4247

4348
CumulativeSumMsgSize uint64 `json:"-"`
@@ -52,8 +57,34 @@ func (m *BroadcastFeedMessage) UpdateCumulativeSumMsgSize(val uint64) {
5257
m.CumulativeSumMsgSize += val + m.Size()
5358
}
5459

55-
func (m *BroadcastFeedMessage) Hash(chainId uint64) (common.Hash, error) {
56-
return m.Message.Hash(m.SequenceNumber, chainId)
60+
// SignatureHash creates a hash for the feed message that include all fields that need to
61+
// be signed. Be aware that changing this function can break compatibility with older clients.
62+
func (m *BroadcastFeedMessage) SignatureHash(chainId uint64) common.Hash {
63+
data := []byte{}
64+
data = append(data, uniquifyingPrefix...)
65+
66+
data = binary.BigEndian.AppendUint64(data, chainId)
67+
data = binary.BigEndian.AppendUint64(data, uint64(m.SequenceNumber))
68+
if m.BlockHash != nil {
69+
data = append(data, m.BlockHash.Bytes()...)
70+
}
71+
data = append(data, m.BlockMetadata...)
72+
data = binary.BigEndian.AppendUint64(data, m.Message.DelayedMessagesRead)
73+
74+
l1IncomingMessage := m.Message.Message
75+
data = append(data, l1IncomingMessage.Header.Kind)
76+
data = append(data, l1IncomingMessage.Header.Poster.Bytes()...)
77+
data = binary.BigEndian.AppendUint64(data, l1IncomingMessage.Header.BlockNumber)
78+
data = binary.BigEndian.AppendUint64(data, l1IncomingMessage.Header.Timestamp)
79+
if l1IncomingMessage.Header.RequestId != nil {
80+
data = append(data, l1IncomingMessage.Header.RequestId.Bytes()...)
81+
}
82+
if l1IncomingMessage.Header.L1BaseFee != nil {
83+
data = append(data, l1IncomingMessage.Header.L1BaseFee.Bytes()...)
84+
}
85+
data = append(data, l1IncomingMessage.L2msg...)
86+
87+
return crypto.Keccak256Hash(data)
5788
}
5889

5990
type ConfirmedSequenceNumberMessage struct {

broadcaster/message/message_serialization_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func ExampleBroadcastMessage_broadcastfeedmessageWithBlockHashAndBlockMetadata()
4545
encoder := json.NewEncoder(&buf)
4646
_ = encoder.Encode(msg)
4747
fmt.Println(buf.String())
48-
// Output: {"version":1,"messages":[{"sequenceNumber":12345,"message":{"message":{"header":{"kind":0,"sender":"0x0000000000000000000000000000000000000000","blockNumber":0,"timestamp":0,"requestId":"0x0000000000000000000000000000000000000000000000000000000000000000","baseFeeL1":0},"l2Msg":"3q2+7w=="},"delayedMessagesRead":3333},"blockHash":"0xff00000000000000000000000000000000000000000000000000000000000000","signature":null,"blockMetadata":"AAI="}]}
48+
// Output: {"version":1,"messages":[{"sequenceNumber":12345,"message":{"message":{"header":{"kind":0,"sender":"0x0000000000000000000000000000000000000000","blockNumber":0,"timestamp":0,"requestId":"0x0000000000000000000000000000000000000000000000000000000000000000","baseFeeL1":0},"l2Msg":"3q2+7w=="},"delayedMessagesRead":3333},"blockHash":"0xff00000000000000000000000000000000000000000000000000000000000000","signatureV2":null,"blockMetadata":"AAI="}]}
4949
}
5050

5151
func ExampleBroadcastMessage_broadcastfeedmessageWithoutBlockHashAndBlockMetadata() {
@@ -78,7 +78,7 @@ func ExampleBroadcastMessage_broadcastfeedmessageWithoutBlockHashAndBlockMetadat
7878
encoder := json.NewEncoder(&buf)
7979
_ = encoder.Encode(msg)
8080
fmt.Println(buf.String())
81-
// Output: {"version":1,"messages":[{"sequenceNumber":12345,"message":{"message":{"header":{"kind":0,"sender":"0x0000000000000000000000000000000000000000","blockNumber":0,"timestamp":0,"requestId":"0x0000000000000000000000000000000000000000000000000000000000000000","baseFeeL1":0},"l2Msg":"3q2+7w=="},"delayedMessagesRead":3333},"signature":null}]}
81+
// Output: {"version":1,"messages":[{"sequenceNumber":12345,"message":{"message":{"header":{"kind":0,"sender":"0x0000000000000000000000000000000000000000","blockNumber":0,"timestamp":0,"requestId":"0x0000000000000000000000000000000000000000000000000000000000000000","baseFeeL1":0},"l2Msg":"3q2+7w=="},"delayedMessagesRead":3333},"signatureV2":null}]}
8282
}
8383

8484
func ExampleBroadcastMessage_emptymessage() {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2025, Offchain Labs, Inc.
2+
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE.md
3+
4+
package message
5+
6+
import (
7+
"math/big"
8+
"testing"
9+
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/ethereum/go-ethereum/common"
13+
14+
"github.com/offchainlabs/nitro/arbos/arbostypes"
15+
)
16+
17+
func TestBroadcastFeedMessageSignature(t *testing.T) {
18+
var requestId common.Hash
19+
msg := BroadcastFeedMessage{
20+
SequenceNumber: 12345,
21+
Message: arbostypes.MessageWithMetadata{
22+
Message: &arbostypes.L1IncomingMessage{
23+
Header: &arbostypes.L1IncomingMessageHeader{
24+
Kind: 0,
25+
Poster: [20]byte{},
26+
BlockNumber: 0,
27+
Timestamp: 0,
28+
RequestId: &requestId,
29+
L1BaseFee: big.NewInt(0),
30+
},
31+
L2msg: []byte{0xde, 0xad, 0xbe, 0xef},
32+
},
33+
DelayedMessagesRead: 3333,
34+
},
35+
Signature: nil,
36+
BlockMetadata: []byte{0xde, 0xad, 0xbe, 0xaf},
37+
}
38+
39+
const chainId = 0xa4b1
40+
hash := msg.SignatureHash(chainId)
41+
// Compare against hard-coded hash to ensure it won't break in the future
42+
expected := common.HexToHash("0x3d79853de5f9e4354e5d6c6d4cad19dcd969f9646f0cab21e5bdfee4902dfa2e")
43+
require.Equal(t, expected, hash)
44+
}

0 commit comments

Comments
 (0)