update VAA parsing and structure
Change-Id: Ifd712050645b1b3fad0f8bf5b2227c0fdf89df84
This commit is contained in:
parent
14c8606a8e
commit
844bd3d817
|
@ -49,8 +49,8 @@ func (p *Processor) handleLockup(ctx context.Context, k *common.MessagePublicati
|
||||||
)
|
)
|
||||||
|
|
||||||
lockupsObservedTotal.With(prometheus.Labels{
|
lockupsObservedTotal.With(prometheus.Labels{
|
||||||
"source_chain": k.SourceChain.String(),
|
"emitter_chain": k.EmitterChain.String(),
|
||||||
"target_chain": k.TargetChain.String()}).Add(1)
|
}).Add(1)
|
||||||
|
|
||||||
// All nodes will create the exact same VAA and sign its digest.
|
// All nodes will create the exact same VAA and sign its digest.
|
||||||
// Consensus is established on this digest.
|
// Consensus is established on this digest.
|
||||||
|
@ -60,19 +60,10 @@ func (p *Processor) handleLockup(ctx context.Context, k *common.MessagePublicati
|
||||||
GuardianSetIndex: p.gs.Index,
|
GuardianSetIndex: p.gs.Index,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
Timestamp: k.Timestamp,
|
Timestamp: k.Timestamp,
|
||||||
Payload: &vaa.BodyTransfer{
|
|
||||||
Nonce: k.Nonce,
|
Nonce: k.Nonce,
|
||||||
SourceChain: k.SourceChain,
|
EmitterChain: k.EmitterChain,
|
||||||
TargetChain: k.TargetChain,
|
EmitterAddress: k.EmitterAddress,
|
||||||
SourceAddress: k.SourceAddress,
|
Payload: k.Payload,
|
||||||
TargetAddress: k.TargetAddress,
|
|
||||||
Asset: &vaa.AssetMeta{
|
|
||||||
Chain: k.TokenChain,
|
|
||||||
Address: k.TokenAddress,
|
|
||||||
Decimals: k.TokenDecimals,
|
|
||||||
},
|
|
||||||
Amount: k.Amount,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate digest of the unsigned VAA.
|
// Generate digest of the unsigned VAA.
|
||||||
|
@ -87,16 +78,14 @@ func (p *Processor) handleLockup(ctx context.Context, k *common.MessagePublicati
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.logger.Info("observed and signed confirmed lockup",
|
p.logger.Info("observed and signed confirmed message publication",
|
||||||
zap.Stringer("source_chain", k.SourceChain),
|
zap.Stringer("source_chain", k.EmitterChain),
|
||||||
zap.Stringer("target_chain", k.TargetChain),
|
|
||||||
zap.Stringer("txhash", k.TxHash),
|
zap.Stringer("txhash", k.TxHash),
|
||||||
zap.String("digest", hex.EncodeToString(digest.Bytes())),
|
zap.String("digest", hex.EncodeToString(digest.Bytes())),
|
||||||
zap.String("signature", hex.EncodeToString(s)))
|
zap.String("signature", hex.EncodeToString(s)))
|
||||||
|
|
||||||
lockupsSignedTotal.With(prometheus.Labels{
|
lockupsSignedTotal.With(prometheus.Labels{
|
||||||
"source_chain": k.SourceChain.String(),
|
"emitter_chain": k.EmitterChain.String()}).Add(1)
|
||||||
"target_chain": k.TargetChain.String()}).Add(1)
|
|
||||||
|
|
||||||
p.broadcastSignature(v, s)
|
p.broadcastSignature(v, s)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -26,8 +25,14 @@ type (
|
||||||
|
|
||||||
// Timestamp when the VAA was created
|
// Timestamp when the VAA was created
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
// Payload of the VAA. This describes the action to be performed
|
// Nonce of the VAA
|
||||||
Payload vaaBody
|
Nonce uint32
|
||||||
|
// EmitterChain the VAA was emitted on
|
||||||
|
EmitterChain ChainID
|
||||||
|
// EmitterAddress of the contract that emitted the Message
|
||||||
|
EmitterAddress Address
|
||||||
|
// Payload of the message
|
||||||
|
Payload []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainID of a Wormhole chain
|
// ChainID of a Wormhole chain
|
||||||
|
@ -46,52 +51,6 @@ type (
|
||||||
// Signature data
|
// Signature data
|
||||||
Signature [65]byte // TODO: hex marshaller
|
Signature [65]byte // TODO: hex marshaller
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssetMeta describes an asset within the Wormhole protocol
|
|
||||||
AssetMeta struct {
|
|
||||||
// Chain is the ID of the chain the original version of the asset exists on
|
|
||||||
Chain ChainID
|
|
||||||
// Address is the address of the token contract/mint/equivalent.
|
|
||||||
Address Address
|
|
||||||
// Decimals is the number of decimals the token has
|
|
||||||
Decimals uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
vaaBody interface {
|
|
||||||
getActionID() Action
|
|
||||||
serialize() ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
BodyTransfer struct {
|
|
||||||
// Nonce is a user given unique nonce for this transfer
|
|
||||||
Nonce uint32
|
|
||||||
// SourceChain is the id of the chain the transfer was initiated from
|
|
||||||
SourceChain ChainID
|
|
||||||
// TargetChain is the id of the chain the transfer is directed to
|
|
||||||
TargetChain ChainID
|
|
||||||
// TargetAddress is the address of the sender on SourceChain
|
|
||||||
SourceAddress Address
|
|
||||||
// TargetAddress is the address of the recipient on TargetChain
|
|
||||||
TargetAddress Address
|
|
||||||
// Asset is the asset to be transferred
|
|
||||||
Asset *AssetMeta
|
|
||||||
// Amount is the amount of tokens to be transferred
|
|
||||||
Amount *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
BodyGuardianSetUpdate struct {
|
|
||||||
// Key is the new guardian set key
|
|
||||||
Keys []common.Address
|
|
||||||
// NewIndex is the index of the new guardian set
|
|
||||||
NewIndex uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
BodyContractUpgrade struct {
|
|
||||||
// ChainID is the chain on which the contract should be upgraded
|
|
||||||
ChainID uint8
|
|
||||||
// NewContract is the address of the account containing the new contract.
|
|
||||||
NewContract Address
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a Address) String() string {
|
func (a Address) String() string {
|
||||||
|
@ -112,10 +71,6 @@ func (c ChainID) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ActionGuardianSetUpdate Action = 0x01
|
|
||||||
ActionContractUpgrade Action = 0x02
|
|
||||||
ActionTransfer Action = 0x10
|
|
||||||
|
|
||||||
// ChainIDSolana is the ChainID of Solana
|
// ChainIDSolana is the ChainID of Solana
|
||||||
ChainIDSolana = 1
|
ChainIDSolana = 1
|
||||||
// ChainIDEthereum is the ChainID of Ethereum
|
// ChainIDEthereum is the ChainID of Ethereum
|
||||||
|
@ -174,30 +129,25 @@ func Unmarshal(data []byte) (*VAA, error) {
|
||||||
}
|
}
|
||||||
v.Timestamp = time.Unix(int64(unixSeconds), 0)
|
v.Timestamp = time.Unix(int64(unixSeconds), 0)
|
||||||
|
|
||||||
var (
|
if err := binary.Read(reader, binary.BigEndian, &v.Nonce); err != nil {
|
||||||
action uint8
|
return nil, fmt.Errorf("failed to read nonce: %w", err)
|
||||||
)
|
|
||||||
if err := binary.Read(reader, binary.BigEndian, &action); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read action: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPos := len(data) - reader.Len()
|
if err := binary.Read(reader, binary.BigEndian, &v.EmitterChain); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read emitter chain: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
payloadReader := bytes.NewReader(data[currentPos:])
|
emitterAddress := Address{}
|
||||||
var err error
|
if n, err := reader.Read(emitterAddress[:]); err != nil || n != 32 {
|
||||||
switch Action(action) {
|
return nil, fmt.Errorf("failed to read emitter address [%d]: %w", n, err)
|
||||||
case ActionGuardianSetUpdate:
|
|
||||||
v.Payload, err = parseBodyGuardianSetUpdate(payloadReader)
|
|
||||||
case ActionTransfer:
|
|
||||||
v.Payload, err = parseBodyTransfer(payloadReader)
|
|
||||||
case ActionContractUpgrade:
|
|
||||||
v.Payload, err = parseBodyContractUpgrade(payloadReader)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown action: %d", action)
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse payload: %w", err)
|
payload := make([]byte, 1000)
|
||||||
|
n, err := reader.Read(payload)
|
||||||
|
if err != nil || n == 0 {
|
||||||
|
return nil, fmt.Errorf("failed to read payload [%d]: %w", n, err)
|
||||||
}
|
}
|
||||||
|
v.Payload = payload[:n]
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
@ -275,14 +225,10 @@ func (v *VAA) Marshal() ([]byte, error) {
|
||||||
func (v *VAA) serializeBody() ([]byte, error) {
|
func (v *VAA) serializeBody() ([]byte, error) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
MustWrite(buf, binary.BigEndian, uint32(v.Timestamp.Unix()))
|
MustWrite(buf, binary.BigEndian, uint32(v.Timestamp.Unix()))
|
||||||
MustWrite(buf, binary.BigEndian, v.Payload.getActionID())
|
MustWrite(buf, binary.BigEndian, v.Nonce)
|
||||||
|
MustWrite(buf, binary.BigEndian, v.EmitterChain)
|
||||||
payloadData, err := v.Payload.serialize()
|
buf.Write(v.EmitterAddress[:])
|
||||||
if err != nil {
|
buf.Write(v.Payload)
|
||||||
return nil, fmt.Errorf("failed to serialize payload: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.Write(payloadData)
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
@ -305,141 +251,6 @@ func (v *VAA) AddSignature(key *ecdsa.PrivateKey, index uint8) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBodyTransfer(r io.Reader) (*BodyTransfer, error) {
|
|
||||||
b := &BodyTransfer{}
|
|
||||||
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.Nonce); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.SourceChain); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read source chain: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.TargetChain); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read target chain: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := r.Read(b.SourceAddress[:]); err != nil || n != 32 {
|
|
||||||
return nil, fmt.Errorf("failed to read source address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := r.Read(b.TargetAddress[:]); err != nil || n != 32 {
|
|
||||||
return nil, fmt.Errorf("failed to read target address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Asset = &AssetMeta{}
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.Asset.Chain); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read asset chain: %w", err)
|
|
||||||
}
|
|
||||||
if n, err := r.Read(b.Asset.Address[:]); err != nil || n != 32 {
|
|
||||||
return nil, fmt.Errorf("failed to read asset address: %w", err)
|
|
||||||
}
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.Asset.Decimals); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read asset decimals: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var amountBytes [32]byte
|
|
||||||
if n, err := r.Read(amountBytes[:]); err != nil || n != 32 {
|
|
||||||
return nil, fmt.Errorf("failed to read amount: %w", err)
|
|
||||||
}
|
|
||||||
b.Amount = new(big.Int).SetBytes(amountBytes[:])
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BodyTransfer) getActionID() Action {
|
|
||||||
return ActionTransfer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BodyTransfer) serialize() ([]byte, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
MustWrite(buf, binary.BigEndian, v.Nonce)
|
|
||||||
MustWrite(buf, binary.BigEndian, v.SourceChain)
|
|
||||||
MustWrite(buf, binary.BigEndian, v.TargetChain)
|
|
||||||
buf.Write(v.SourceAddress[:])
|
|
||||||
buf.Write(v.TargetAddress[:])
|
|
||||||
|
|
||||||
if v.Asset == nil {
|
|
||||||
return nil, fmt.Errorf("asset is empty")
|
|
||||||
}
|
|
||||||
MustWrite(buf, binary.BigEndian, v.Asset.Chain)
|
|
||||||
buf.Write(v.Asset.Address[:])
|
|
||||||
MustWrite(buf, binary.BigEndian, v.Asset.Decimals)
|
|
||||||
|
|
||||||
if v.Amount == nil {
|
|
||||||
return nil, fmt.Errorf("amount is empty")
|
|
||||||
}
|
|
||||||
buf.Write(common.LeftPadBytes(v.Amount.Bytes(), 32))
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBodyGuardianSetUpdate(r io.Reader) (*BodyGuardianSetUpdate, error) {
|
|
||||||
b := &BodyGuardianSetUpdate{}
|
|
||||||
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.NewIndex); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read new index: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyLen := uint8(0)
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &keyLen); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read guardianset key len: %w", err)
|
|
||||||
}
|
|
||||||
for i := 0; i < int(keyLen); i++ {
|
|
||||||
key := common.Address{}
|
|
||||||
if n, err := r.Read(key[:]); err != nil || n != 20 {
|
|
||||||
return nil, fmt.Errorf("failed to read guardianset key [%d]: %w", i, err)
|
|
||||||
}
|
|
||||||
b.Keys = append(b.Keys, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BodyGuardianSetUpdate) getActionID() Action {
|
|
||||||
return ActionGuardianSetUpdate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BodyGuardianSetUpdate) serialize() ([]byte, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
MustWrite(buf, binary.BigEndian, v.NewIndex)
|
|
||||||
MustWrite(buf, binary.BigEndian, uint8(len(v.Keys)))
|
|
||||||
for _, key := range v.Keys {
|
|
||||||
buf.Write(key.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBodyContractUpgrade(r io.Reader) (*BodyContractUpgrade, error) {
|
|
||||||
b := &BodyContractUpgrade{}
|
|
||||||
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &b.ChainID); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read chain id: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := r.Read(b.NewContract[:]); err != nil || n != 32 {
|
|
||||||
return nil, fmt.Errorf("failed to read new contract address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BodyContractUpgrade) getActionID() Action {
|
|
||||||
return ActionContractUpgrade
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *BodyContractUpgrade) serialize() ([]byte, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
MustWrite(buf, binary.BigEndian, v.ChainID)
|
|
||||||
buf.Write(v.NewContract[:])
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustWrite calls binary.Write and panics on errors
|
// MustWrite calls binary.Write and panics on errors
|
||||||
func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) {
|
func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) {
|
||||||
if err := binary.Write(w, order, data); err != nil {
|
if err := binary.Write(w, order, data); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue