Skip to content

Commit

Permalink
Merge pull request #2099 from OffchainLabs/4844-inbox-reader-fixes
Browse files Browse the repository at this point in the history
4844 inbox reader fixes
  • Loading branch information
PlasmaPower authored Jan 24, 2024
2 parents 2bd34c6 + 13ed4c6 commit eb7d6f8
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 21 deletions.
44 changes: 27 additions & 17 deletions arbnode/blob_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"path"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/offchainlabs/nitro/arbutil"
"github.com/offchainlabs/nitro/util/blobs"
"github.com/offchainlabs/nitro/util/jsonapi"
"github.com/offchainlabs/nitro/util/pretty"

"github.com/spf13/pflag"
)

type BlobClient struct {
config BlobClientConfig
ec arbutil.L1Interface
beaconUrl *url.URL
httpClient *http.Client

// The genesis time time and seconds per slot won't change so only request them once.
Expand All @@ -43,12 +45,16 @@ func BlobClientAddOptions(prefix string, f *pflag.FlagSet) {
f.String(prefix+".beacon-chain-url", DefaultBlobClientConfig.BeaconChainUrl, "Beacon Chain url to use for fetching blobs")
}

func NewBlobClient(config BlobClientConfig, ec arbutil.L1Interface) *BlobClient {
func NewBlobClient(config BlobClientConfig, ec arbutil.L1Interface) (*BlobClient, error) {
beaconUrl, err := url.Parse(config.BeaconChainUrl)
if err != nil {
return nil, fmt.Errorf("failed to parse beacon chain URL: %w", err)
}
return &BlobClient{
config: config,
ec: ec,
beaconUrl: beaconUrl,
httpClient: &http.Client{},
}
}, nil
}

type fullResult[T any] struct {
Expand All @@ -60,7 +66,11 @@ func beaconRequest[T interface{}](b *BlobClient, ctx context.Context, beaconPath

var empty T

req, err := http.NewRequestWithContext(ctx, "GET", path.Join(b.config.BeaconChainUrl, beaconPath), http.NoBody)
// not really a deep copy, but copies the Path part we care about
url := *b.beaconUrl
url.Path = path.Join(url.Path, beaconPath)

req, err := http.NewRequestWithContext(ctx, "GET", url.String(), http.NoBody)
if err != nil {
return empty, err
}
Expand Down Expand Up @@ -103,14 +113,14 @@ func (b *BlobClient) GetBlobs(ctx context.Context, blockHash common.Hash, versio
}

type blobResponseItem struct {
BlockRoot string `json:"block_root"`
Index int `json:"index"`
Slot uint64 `json:"slot"`
BlockParentRoot string `json:"block_parent_root"`
ProposerIndex uint64 `json:"proposer_index"`
Blob hexutil.Bytes `json:"blob"`
KzgCommitment hexutil.Bytes `json:"kzg_commitment"`
KzgProof hexutil.Bytes `json:"kzg_proof"`
BlockRoot string `json:"block_root"`
Index jsonapi.Uint64String `json:"index"`
Slot jsonapi.Uint64String `json:"slot"`
BlockParentRoot string `json:"block_parent_root"`
ProposerIndex jsonapi.Uint64String `json:"proposer_index"`
Blob hexutil.Bytes `json:"blob"`
KzgCommitment hexutil.Bytes `json:"kzg_commitment"`
KzgProof hexutil.Bytes `json:"kzg_proof"`
}

func (b *BlobClient) blobSidecars(ctx context.Context, slot uint64, versionedHashes []common.Hash) ([]kzg4844.Blob, error) {
Expand Down Expand Up @@ -172,7 +182,7 @@ func (b *BlobClient) blobSidecars(ctx context.Context, slot uint64, versionedHas
}

type genesisResponse struct {
GenesisTime uint64 `json:"genesis_time"`
GenesisTime jsonapi.Uint64String `json:"genesis_time"`
// don't currently care about other fields, add if needed
}

Expand All @@ -184,12 +194,12 @@ func (b *BlobClient) genesisTime(ctx context.Context) (uint64, error) {
if err != nil {
return 0, fmt.Errorf("error calling beacon client in genesisTime: %w", err)
}
b.cachedGenesisTime = gr.GenesisTime
b.cachedGenesisTime = uint64(gr.GenesisTime)
return b.cachedGenesisTime, nil
}

type getSpecResponse struct {
SecondsPerSlot uint64 `json:"SECONDS_PER_SLOT"`
SecondsPerSlot jsonapi.Uint64String `json:"SECONDS_PER_SLOT"`
}

func (b *BlobClient) secondsPerSlot(ctx context.Context) (uint64, error) {
Expand All @@ -200,7 +210,7 @@ func (b *BlobClient) secondsPerSlot(ctx context.Context) (uint64, error) {
if err != nil {
return 0, fmt.Errorf("error calling beacon client in secondsPerSlot: %w", err)
}
b.cachedSecondsPerSlot = gr.SecondsPerSlot
b.cachedSecondsPerSlot = uint64(gr.SecondsPerSlot)
return b.cachedSecondsPerSlot, nil

}
5 changes: 4 additions & 1 deletion arbnode/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,10 @@ func createNodeImpl(

var blobReader arbstate.BlobReader
if config.BlobClient.BeaconChainUrl != "" {
blobReader = NewBlobClient(config.BlobClient, l1client)
blobReader, err = NewBlobClient(config.BlobClient, l1client)
if err != nil {
return nil, err
}
}

inboxTracker, err := NewInboxTracker(arbDb, txStreamer, daReader, blobReader)
Expand Down
15 changes: 15 additions & 0 deletions arbnode/sequencer_inbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/offchainlabs/nitro/arbstate"
"github.com/offchainlabs/nitro/arbutil"

"github.com/offchainlabs/nitro/solgen/go/bridgegen"
Expand All @@ -33,6 +34,7 @@ const (
batchDataTxInput batchDataLocation = iota
batchDataSeparateEvent
batchDataNone
batchDataBlobHashes
)

func init() {
Expand Down Expand Up @@ -149,6 +151,19 @@ func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client arbut
case batchDataNone:
// No data when in a force inclusion batch
return nil, nil
case batchDataBlobHashes:
tx, err := arbutil.GetLogTransaction(ctx, client, m.rawLog)
if err != nil {
return nil, err
}
if len(tx.BlobHashes()) == 0 {
return nil, fmt.Errorf("blob batch transaction %v has no blobs", tx.Hash())
}
data := []byte{arbstate.BlobHashesHeaderFlag}
for _, h := range tx.BlobHashes() {
data = append(data, h[:]...)
}
return data, nil
default:
return nil, fmt.Errorf("batch has invalid data location %v", m.dataLocation)
}
Expand Down
12 changes: 10 additions & 2 deletions arbutil/transaction_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)

// GetLogEmitterTxData requires that the tx's data is at least 4 bytes long
func GetLogEmitterTxData(ctx context.Context, client L1Interface, log types.Log) ([]byte, error) {
func GetLogTransaction(ctx context.Context, client L1Interface, log types.Log) (*types.Transaction, error) {
tx, err := client.TransactionInBlock(ctx, log.BlockHash, log.TxIndex)
if err != nil {
return nil, err
}
if tx.Hash() != log.TxHash {
return nil, fmt.Errorf("L1 client returned unexpected transaction hash %v when looking up block %v transaction %v with expected hash %v", tx.Hash(), log.BlockHash, log.TxIndex, log.TxHash)
}
return tx, nil
}

// GetLogEmitterTxData requires that the tx's data is at least 4 bytes long
func GetLogEmitterTxData(ctx context.Context, client L1Interface, log types.Log) ([]byte, error) {
tx, err := GetLogTransaction(ctx, client, log)
if err != nil {
return nil, err
}
if len(tx.Data()) < 4 {
return nil, fmt.Errorf("log emitting transaction %v unexpectedly does not have enough data", tx.Hash())
}
Expand Down
3 changes: 2 additions & 1 deletion util/blobs/blobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package blobs

import (
"bytes"
"crypto/sha256"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -47,7 +48,7 @@ func DecodeBlobs(blobs []kzg4844.Blob) ([]byte, error) {
}
}
var outputData []byte
err := rlp.DecodeBytes(rlpData, &outputData)
err := rlp.Decode(bytes.NewReader(rlpData), &outputData)
return outputData, err
}

Expand Down
32 changes: 32 additions & 0 deletions util/jsonapi/uint64_string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2024, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE

package jsonapi

import (
"fmt"
"strconv"
)

// Uint64String is a uint64 that JSON marshals and unmarshals as string in decimal
type Uint64String uint64

func (u *Uint64String) UnmarshalJSON(b []byte) error {
s := string(b)
if s == "null" {
return nil
}

// Parse string as uint64, removing quotes
value, err := strconv.ParseUint(s[1:len(s)-1], 10, 64)
if err != nil {
return err
}

*u = Uint64String(value)
return nil
}

func (u Uint64String) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%d\"", uint64(u))), nil
}

0 comments on commit eb7d6f8

Please sign in to comment.