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

import (
	"context"
	"errors"
	"fmt"

8
	"github.com/ethereum/go-ethereum"
9 10

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

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

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

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

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

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

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

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

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

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