[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/evstack/ev-node/main/types/data.go [Back]  [Original]

package types

import (
	"bytes"
	"encoding"
	"errors"
	"time"

	"google.golang.org/protobuf/proto"
)

var (
	// ErrHeaderDataMismatch is returned when header and data metadata do not describe the same block.
	ErrHeaderDataMismatch = errors.New("header and data do not match")

	// ErrDataHashMismatch is returned when a header's data hash does not match its block data.
	ErrDataHashMismatch = errors.New("dataHash from the header does not match with hash of the block's data")
)

// Version captures the consensus rules for processing a block in the blockchain,
// including all blockchain data structures and the rules of the application's
// state transition machine.
// This is equivalent to the tmversion.Consensus type in Tendermint.
type Version struct {
	Block uint64
	App   uint64
}

var _ encoding.BinaryMarshaler = &Data{}
var _ encoding.BinaryUnmarshaler = &Data{}

// Metadata defines metadata for Data struct to help with p2p gossiping.
type Metadata struct {
	ChainID      string
	Height       uint64
	Time         uint64
	LastDataHash Hash
}

// Data defines Evolve block data.
type Data struct {
	*Metadata
	Txs Txs
}

// SignedData combines Data and its signature.
type SignedData struct {
	Data
	Signature Signature
	Signer    Signer
}

// Signature represents signature of block creator.
type Signature []byte

// ValidateBasic performs basic validation of a signature.
func (signature *Signature) ValidateBasic() error {
	if len(*signature) == 0 {
		return ErrSignatureEmpty
	}
	return nil
}

// Validate performs validation of data with respect to its header
func Validate(header *SignedHeader, data *Data) error {
	// Validate Metadata only when available
	if data.Metadata != nil {
		if header.ChainID() != data.ChainID() ||
			header.Height() != data.Height() ||
			header.Time() != data.Time() { // skipping LastDataHash comparison as it needs access to previous header
			return ErrHeaderDataMismatch
		}
	}
	// exclude Metadata while computing the data hash for comparison
	d := Data{Txs: data.Txs}
	dataHash := d.DACommitment()
	if !bytes.Equal(dataHash[:], header.DataHash[:]) {
		return ErrDataHashMismatch
	}
	return nil
}

// New returns a new Block.
func (d *Data) New() *Data {
	return new(Data)
}

// IsZero returns true if the block is nil.
func (d *Data) IsZero() bool {
	return d == nil
}

// ChainID returns chain ID of the block.
func (d *Data) ChainID() string {
	return d.Metadata.ChainID
}

// Height returns height of the block.
func (d *Data) Height() uint64 {
	return d.Metadata.Height
}

// LastHeader returns last header hash of the block.
func (d *Data) LastHeader() Hash {
	return d.LastDataHash
}

// Time returns time of the block.
func (d *Data) Time() time.Time {
	return time.Unix(0, int64(d.Metadata.Time))
}

// Verify Verifies a new, untrusted block against a trusted block.
func (d *Data) Verify(untrustedData *Data) error {
	if untrustedData == nil {
		return errors.New("untrusted block cannot be nil")
	}
	dataHash := d.Hash()
	// Check if the data hash of the untrusted block matches the last data hash of the trusted block
	if !bytes.Equal(dataHash[:], untrustedData.LastDataHash[:]) {
		return errors.New("data hash of the trusted data does not match with last data hash of the untrusted data")
	}
	return nil
}

// Validate performs basic validation of a block.
// this is used to implement the header interface for go header
func (d *Data) Validate() error {
	// Validate that Metadata is set
	if d.Metadata == nil {
		return errors.New("data metadata cannot be nil")
	}

	// Validate ChainID is not empty
	if d.Metadata.ChainID == "" {
		return errors.New("chain ID cannot be empty")
	}

	// Validate Height is non-zero for non-genesis blocks
	if d.Metadata.Height == 0 {
		return errors.New("height cannot be zero")
	}

	// Validate timestamp - must be non-zero
	if d.Metadata.Time == 0 {
		return errors.New("timestamp cannot be zero")
	}

	// Check timestamp is not too far in the future (allow some clock drift)
	maxAllowedTime := time.Now().Add(MaxClockDrift)
	dataTime := d.Time()
	if dataTime.After(maxAllowedTime) {
		return errors.New("timestamp too far in future")
	}

	return nil
}

// Size returns size of the block in bytes.
func (d *Data) Size() int {
	return proto.Size(d.ToProto())
}

// TxsByteSize returns total byte size of all transactions without proto marshalling.
// This is much cheaper than Size() and useful for metrics/reporting.
func (d *Data) TxsByteSize() int {
	n := 0
	for _, tx := range d.Txs {
		n += len(tx)
	}
	return n
}

Web Proxy Viewer  |  New URL  |  Original Page