mirror of
https://github.com/luxfi/bft.git
synced 2026-10-30 17:01:54 +00:00
75 lines
2.1 KiB
Go
75 lines
2.1 KiB
Go
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package wal
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"hash/crc64"
|
|
"io"
|
|
)
|
|
|
|
const (
|
|
recordSizeLen = 4
|
|
recordChecksumLen = 8
|
|
)
|
|
|
|
var ErrInvalidCRC = errors.New("invalid CRC checksum")
|
|
|
|
// writeRecord writes a length-prefixed and check-summed record to the writer.
|
|
func writeRecord(w io.Writer, payload []byte) error {
|
|
checksumIndex := recordSizeLen + len(payload)
|
|
buff := make([]byte, checksumIndex+recordChecksumLen)
|
|
crc := crc64.New(crc64.MakeTable(crc64.ECMA))
|
|
|
|
binary.BigEndian.PutUint32(buff, uint32(len(payload)))
|
|
copy(buff[recordSizeLen:], payload)
|
|
if _, err := crc.Write(buff[:checksumIndex]); err != nil {
|
|
return fmt.Errorf("CRC checksum failed: %w", err)
|
|
}
|
|
|
|
buff = crc.Sum(buff[:checksumIndex])
|
|
_, err := w.Write(buff)
|
|
return err
|
|
}
|
|
|
|
// readRecord reads a length-prefixed and check-summed record from the reader.
|
|
// If the record is read correctly, the number of bytes read is returned.
|
|
func readRecord(r io.Reader, maxSize uint32) ([]byte, uint32, error) {
|
|
const tempSpace = max(recordSizeLen, recordChecksumLen)
|
|
buff := make([]byte, tempSpace)
|
|
crc := crc64.New(crc64.MakeTable(crc64.ECMA))
|
|
|
|
sizeBuff := buff[:recordSizeLen]
|
|
if _, err := io.ReadFull(r, sizeBuff); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
if _, err := crc.Write(sizeBuff); err != nil {
|
|
return nil, 0, fmt.Errorf("CRC checksum failed: %w", err)
|
|
}
|
|
|
|
payloadLen := binary.BigEndian.Uint32(sizeBuff)
|
|
if payloadLen > maxSize {
|
|
return nil, 0, fmt.Errorf("record indicates payload is %d bytes long", payloadLen)
|
|
}
|
|
|
|
payloadAndChecksum := make([]byte, payloadLen+recordChecksumLen)
|
|
if _, err := io.ReadFull(r, payloadAndChecksum); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
payload := payloadAndChecksum[:payloadLen]
|
|
if _, err := crc.Write(payload); err != nil {
|
|
return nil, 0, fmt.Errorf("CRC checksum failed: %w", err)
|
|
}
|
|
|
|
checksum := payloadAndChecksum[payloadLen:]
|
|
expectedChecksum := crc.Sum(buff[:0])
|
|
if !bytes.Equal(checksum, expectedChecksum) {
|
|
return nil, 0, ErrInvalidCRC
|
|
}
|
|
return payload, recordSizeLen + payloadLen + recordChecksumLen, nil
|
|
}
|