collective_beacon.go 5.69 KiB
package collectiveBeacon
import (
"sync"
"github.com/iotaledger/hive.go/stringify"
drngPayload "github.com/iotaledger/goshimmer/packages/binary/drng/payload"
"github.com/iotaledger/goshimmer/packages/binary/drng/payload/header"
"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload"
)
type Payload struct {
//objectstorage.StorableObjectFlags
header header.Header
round uint64 // round of the current beacon
prevSignature []byte // collective signature of the previous beacon
signature []byte // collective signature of the current beacon
dpk []byte // distributed public key
bytes []byte
bytesMutex sync.RWMutex
}
func New(instanceID uint32, round uint64, prevSignature, signature, dpk []byte) *Payload {
return &Payload{
header: header.New(header.CollectiveBeaconType(), instanceID),
round: round,
prevSignature: prevSignature,
signature: signature,
dpk: dpk,
}
}
func (p *Payload) SubType() header.Type {
return p.header.PayloadType()
}
func (payload *Payload) Instance() uint32 {
return payload.header.Instance()
}
func (payload *Payload) Round() uint64 {
return payload.round
}
func (payload *Payload) PrevSignature() []byte {
return payload.prevSignature
}
func (payload *Payload) Signature() []byte {
return payload.signature
}
func (payload *Payload) DistributedPK() []byte {
return payload.dpk
}
// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package.
func Parse(marshalUtil *marshalutil.MarshalUtil) (*Payload, error) {
if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil {
return &Payload{}, err
} else {
return payload.(*Payload), nil
}
}
// FromBytes parses the marshaled version of a Payload into an object.
// It either returns a new Payload or fills an optionally provided Payload with the parsed information.
func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
result = &Payload{}
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to OutputFromBytes")
}
// initialize helper
marshalUtil := marshalutil.New(bytes)
// read information that are required to identify the payload from the outside
if _, err = marshalUtil.ReadUint32(); err != nil {
return
}
if _, err = marshalUtil.ReadUint32(); err != nil {
return
}
// parse header
if result.header, err = header.Parse(marshalUtil); err != nil {
return
}
// parse round
if result.round, err = marshalUtil.ReadUint64(); err != nil {
return
}
// parse prevSignature
if result.prevSignature, err = marshalUtil.ReadBytes(SignatureSize); err != nil {
return
}
// parse current signature
if result.signature, err = marshalUtil.ReadBytes(SignatureSize); err != nil {
return
}
// parse distributed public key
if result.dpk, err = marshalUtil.ReadBytes(PublicKeySize); err != nil {
return
}
// return the number of bytes we processed
consumedBytes = marshalUtil.ReadOffset()
// store bytes, so we don't have to marshal manually
result.bytes = bytes[:consumedBytes]
return
}
func (payload *Payload) Bytes() (bytes []byte) {
// acquire lock for reading bytes
payload.bytesMutex.RLock()
// return if bytes have been determined already
if bytes = payload.bytes; bytes != nil {
defer payload.bytesMutex.RUnlock()
return
}
// switch to write lock
payload.bytesMutex.RUnlock()
payload.bytesMutex.Lock()
defer payload.bytesMutex.Unlock()
// return if bytes have been determined in the mean time
if bytes = payload.bytes; bytes != nil {
return
}
// marshal fields
payloadLength := header.Length + marshalutil.UINT64_SIZE + SignatureSize*2 + PublicKeySize
marshalUtil := marshalutil.New(marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + payloadLength)
marshalUtil.WriteUint32(drngPayload.Type)
marshalUtil.WriteUint32(uint32(payloadLength))
marshalUtil.WriteBytes(payload.header.Bytes())
marshalUtil.WriteUint64(payload.Round())
marshalUtil.WriteBytes(payload.PrevSignature())
marshalUtil.WriteBytes(payload.Signature())
marshalUtil.WriteBytes(payload.DistributedPK())
bytes = marshalUtil.Bytes()
// store result
payload.bytes = bytes
return
}
func (payload *Payload) String() string {
return stringify.Struct("Payload",
stringify.StructField("type", payload.SubType()),
stringify.StructField("instance", payload.Instance()),
stringify.StructField("round", payload.Round()),
stringify.StructField("prevSignature", payload.PrevSignature()),
stringify.StructField("signature", payload.Signature()),
stringify.StructField("distributedPK", payload.DistributedPK()),
)
}
// region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
func (payload *Payload) GetType() payload.Type {
return drngPayload.Type
}
func (payload *Payload) MarshalBinary() (bytes []byte, err error) {
return payload.Bytes(), nil
}
func (payload *Payload) UnmarshalBinary(data []byte) (err error) {
_, err, _ = FromBytes(data, payload)
return
}
// func init() {
// payload.RegisterType(drngPayload.Type, func(data []byte) (payload payload.Payload, err error) {
// payload = &Payload{}
// err = payload.UnmarshalBinary(data)
// return
// })
// }
// define contract (ensure that the struct fulfills the corresponding interface)
var _ payload.Payload = &Payload{}
// // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////