client.go 2.72 KB
Newer Older
1 2 3 4 5 6 7 8
package l1

import (
	"context"
	"errors"
	"fmt"

	"github.com/ethereum-optimism/optimism/op-node/eth"
9
	"github.com/ethereum/go-ethereum"
10 11
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
12
	"github.com/ethereum/go-ethereum/log"
13 14 15
)

var (
16
	ErrNotFound     = ethereum.NotFound
17 18 19 20
	ErrUnknownLabel = errors.New("unknown label")
)

type OracleL1Client struct {
21
	logger               log.Logger
22 23 24 25
	oracle               Oracle
	head                 eth.L1BlockRef
	hashByNum            map[uint64]common.Hash
	earliestIndexedBlock eth.L1BlockRef
26 27
}

28
func NewOracleL1Client(logger log.Logger, oracle Oracle, l1Head common.Hash) *OracleL1Client {
29
	head := eth.InfoToL1BlockRef(oracle.HeaderByBlockHash(l1Head))
30
	logger.Info("L1 head loaded", "hash", head.Hash, "number", head.Number)
31
	return &OracleL1Client{
32
		logger:               logger,
33 34 35 36
		oracle:               oracle,
		head:                 head,
		hashByNum:            map[uint64]common.Hash{head.Number: head.Hash},
		earliestIndexedBlock: head,
37 38 39
	}
}

40
func (o *OracleL1Client) L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L1BlockRef, error) {
41 42
	if label != eth.Unsafe && label != eth.Safe && label != eth.Finalized {
		return eth.L1BlockRef{}, fmt.Errorf("%w: %s", ErrUnknownLabel, label)
43
	}
44 45
	// The L1 head is pre-agreed and unchanging so it can be used for all of unsafe, safe and finalized
	return o.head, nil
46 47
}

48
func (o *OracleL1Client) L1BlockRefByNumber(ctx context.Context, number uint64) (eth.L1BlockRef, error) {
49 50 51
	if number > o.head.Number {
		return eth.L1BlockRef{}, fmt.Errorf("%w: block number %d", ErrNotFound, number)
	}
52 53 54 55 56
	hash, ok := o.hashByNum[number]
	if ok {
		return o.L1BlockRefByHash(ctx, hash)
	}
	block := o.earliestIndexedBlock
57
	o.logger.Info("Extending block by number lookup", "from", block.Number, "to", number)
58
	for block.Number > number {
59
		block = eth.InfoToL1BlockRef(o.oracle.HeaderByBlockHash(block.ParentHash))
60 61
		o.hashByNum[block.Number] = block.Hash
		o.earliestIndexedBlock = block
62
	}
63
	return block, nil
64 65
}

66
func (o *OracleL1Client) L1BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L1BlockRef, error) {
67
	return eth.InfoToL1BlockRef(o.oracle.HeaderByBlockHash(hash)), nil
68 69
}

70
func (o *OracleL1Client) InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) {
71
	return o.oracle.HeaderByBlockHash(hash), nil
72 73
}

74
func (o *OracleL1Client) FetchReceipts(ctx context.Context, blockHash common.Hash) (eth.BlockInfo, types.Receipts, error) {
75
	info, rcpts := o.oracle.ReceiptsByBlockHash(blockHash)
76 77 78
	return info, rcpts, nil
}

79
func (o *OracleL1Client) InfoAndTxsByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, types.Transactions, error) {
80
	info, txs := o.oracle.TransactionsByBlockHash(hash)
81 82
	return info, txs, nil
}