consensus-shipyard / mir

Apache License 2.0
46 stars 14 forks source link

Codegen generate serialization functions #433

Open ranchalp opened 1 year ago

ranchalp commented 1 year ago

If the codegen generated serialization functions, we could remove boilerplate code such as:

func serializePreprepareForHashing(preprepare *pbftpbtypes.Preprepare) *hasherpbtypes.HashData {

    // Encode boolean Aborted field as one byte.
    aborted := byte(0)
    if preprepare.Aborted {
        aborted = 1
    }

    // Put everything together in a slice and return it.
    // Note that we do not include the view number,
    // as the view change protocol might compare hashes of Preprepares across vies.
    return &hasherpbtypes.HashData{Data: [][]byte{preprepare.Sn.Bytes(), {aborted}, preprepare.Data}}
}

func serializeViewChangeForSigning(vc *pbftpbtypes.ViewChange) *cryptopbtypes.SignedData {
    _ = &pbftpb.ViewChange{
        View: 0,
        PSet: nil,
        QSet: nil,
    }

    // Allocate result data structure.
    data := make([][]byte, 0)

    // Encode view number.
    data = append(data, vc.View.Bytes())

    // Encode P set.
    for _, pSetEntry := range vc.PSet {
        data = append(data, pSetEntry.Sn.Bytes())
        data = append(data, pSetEntry.View.Bytes())
        data = append(data, pSetEntry.Digest)
    }

    // Encode Q set.
    for _, qSetEntry := range vc.QSet {
        data = append(data, qSetEntry.Sn.Bytes())
        data = append(data, qSetEntry.View.Bytes())
        data = append(data, qSetEntry.Digest)
    }

    return &cryptopbtypes.SignedData{Data: data}
}
matejpavlovic commented 1 year ago

That's worth considering. A simpler approach achieving a similar result would be to simply use deterministic CBOR serialization of the generated types. Note that in certain cases, we'd still need custom serialization, when, for example, not all fields of a data structure are hashed or signed (e.g., the PBFT view number is, in some cases, excluded when hashing a preprepare message).