|
| 1 | +package ethwal |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + |
| 7 | + "github.com/0xsequence/ethkit/go-ethereum/common" |
| 8 | +) |
| 9 | + |
| 10 | +type BlockHashGetter func(ctx context.Context, blockNum uint64) (common.Hash, error) |
| 11 | + |
| 12 | +func BlockHashGetterFromReader[T any](options Options) BlockHashGetter { |
| 13 | + return func(ctx context.Context, blockNum uint64) (common.Hash, error) { |
| 14 | + reader, err := NewReader[T](options) |
| 15 | + if err != nil { |
| 16 | + return common.Hash{}, fmt.Errorf("failed to create reader: %w", err) |
| 17 | + } |
| 18 | + defer reader.Close() |
| 19 | + |
| 20 | + err = reader.Seek(ctx, blockNum-1) |
| 21 | + if err != nil { |
| 22 | + return common.Hash{}, fmt.Errorf("failed to seek to block %d: %w", blockNum, err) |
| 23 | + } |
| 24 | + |
| 25 | + block, err := reader.Read(ctx) |
| 26 | + if err != nil { |
| 27 | + return common.Hash{}, fmt.Errorf("failed to read block %d: %w", blockNum, err) |
| 28 | + } |
| 29 | + return block.Hash, nil |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +type writerWithVerifyHash[T any] struct { |
| 34 | + Writer[T] |
| 35 | + |
| 36 | + blockHashGetter BlockHashGetter |
| 37 | + |
| 38 | + prevHash common.Hash |
| 39 | +} |
| 40 | + |
| 41 | +var _ Writer[any] = (*writerWithVerifyHash[any])(nil) |
| 42 | + |
| 43 | +func NewWriterWithVerifyHash[T any](writer Writer[T], blockHashGetter BlockHashGetter) Writer[T] { |
| 44 | + return &writerWithVerifyHash[T]{Writer: writer, blockHashGetter: blockHashGetter} |
| 45 | +} |
| 46 | + |
| 47 | +func (w *writerWithVerifyHash[T]) Write(ctx context.Context, b Block[T]) error { |
| 48 | + var err error |
| 49 | + if w.prevHash == (common.Hash{}) && b.Number > 1 { |
| 50 | + w.prevHash, err = w.blockHashGetter(ctx, b.Number-1) |
| 51 | + if err != nil { |
| 52 | + return fmt.Errorf("failed to get block hash: %w", err) |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + if b.Parent != w.prevHash { |
| 57 | + w.prevHash = common.Hash{} |
| 58 | + return fmt.Errorf("parent hash mismatch, expected %s, got %s", |
| 59 | + w.prevHash.String(), b.Parent.String()) |
| 60 | + } |
| 61 | + |
| 62 | + err = w.Writer.Write(ctx, b) |
| 63 | + if err != nil { |
| 64 | + w.prevHash = common.Hash{} |
| 65 | + return fmt.Errorf("failed to write block: %w", err) |
| 66 | + } |
| 67 | + |
| 68 | + w.prevHash = b.Hash |
| 69 | + return nil |
| 70 | +} |
0 commit comments