wormhole/node/pkg/common/chainlock.go

104 lines
2.9 KiB
Go

package common
import (
"bytes"
"encoding/binary"
"fmt"
"time"
"github.com/certusone/wormhole/node/pkg/vaa"
"github.com/ethereum/go-ethereum/common"
)
type MessagePublication struct {
TxHash common.Hash // TODO: rename to identifier? on Solana, this isn't actually the tx hash
Timestamp time.Time
Nonce uint32
Sequence uint64
ConsistencyLevel uint8
EmitterChain vaa.ChainID
EmitterAddress vaa.Address
Payload []byte
}
func (msg *MessagePublication) MessageID() []byte {
return []byte(msg.MessageIDString())
}
func (msg *MessagePublication) MessageIDString() string {
return fmt.Sprintf("%v/%v/%v", uint16(msg.EmitterChain), msg.EmitterAddress, msg.Sequence)
}
const minMsgLength = 88
func (msg *MessagePublication) Marshal() ([]byte, error) {
buf := new(bytes.Buffer)
buf.Write(msg.TxHash[:])
vaa.MustWrite(buf, binary.BigEndian, uint32(msg.Timestamp.Unix()))
vaa.MustWrite(buf, binary.BigEndian, msg.Nonce)
vaa.MustWrite(buf, binary.BigEndian, msg.Sequence)
vaa.MustWrite(buf, binary.BigEndian, msg.ConsistencyLevel)
vaa.MustWrite(buf, binary.BigEndian, msg.EmitterChain)
buf.Write(msg.EmitterAddress[:])
buf.Write(msg.Payload)
return buf.Bytes(), nil
}
// Unmarshal deserializes the binary representation of a VAA
func UnmarshalMessagePublication(data []byte) (*MessagePublication, error) {
if len(data) < minMsgLength {
return nil, fmt.Errorf("message is too short")
}
msg := &MessagePublication{}
reader := bytes.NewReader(data[:])
txHash := common.Hash{}
if n, err := reader.Read(txHash[:]); err != nil || n != 32 {
return nil, fmt.Errorf("failed to read TxHash [%d]: %w", n, err)
}
msg.TxHash = txHash
unixSeconds := uint32(0)
if err := binary.Read(reader, binary.BigEndian, &unixSeconds); err != nil {
return nil, fmt.Errorf("failed to read timestamp: %w", err)
}
msg.Timestamp = time.Unix(int64(unixSeconds), 0)
if err := binary.Read(reader, binary.BigEndian, &msg.Nonce); err != nil {
return nil, fmt.Errorf("failed to read nonce: %w", err)
}
if err := binary.Read(reader, binary.BigEndian, &msg.Sequence); err != nil {
return nil, fmt.Errorf("failed to read sequence: %w", err)
}
if err := binary.Read(reader, binary.BigEndian, &msg.ConsistencyLevel); err != nil {
return nil, fmt.Errorf("failed to read consistency level: %w", err)
}
if err := binary.Read(reader, binary.BigEndian, &msg.EmitterChain); err != nil {
return nil, fmt.Errorf("failed to read emitter chain: %w", err)
}
emitterAddress := vaa.Address{}
if n, err := reader.Read(emitterAddress[:]); err != nil || n != 32 {
return nil, fmt.Errorf("failed to read emitter address [%d]: %w", n, err)
}
msg.EmitterAddress = emitterAddress
payload := make([]byte, vaa.InternalTruncatedPayloadSafetyLimit)
n, err := reader.Read(payload)
if err != nil || n == 0 {
return nil, fmt.Errorf("failed to read payload [%d]: %w", n, err)
}
msg.Payload = payload[:n]
return msg, nil
}