go-blockchain/wire/variant.go
Virgil 050d530b29
Some checks are pending
Security Scan / security (push) Waiting to run
Test / Test (push) Waiting to run
feat(consensus): validate HF5 asset operations
Co-Authored-By: Charon <charon@lethean.io>
2026-04-04 20:14:54 +00:00

101 lines
3.1 KiB
Go

// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// SPDX-License-Identifier: EUPL-1.2
package wire
import (
"bytes"
"fmt"
coreerr "dappco.re/go/core/log"
"dappco.re/go/core/blockchain/types"
)
// VariantElement is one tagged element from a raw variant vector.
// Data contains the raw wire bytes for the element payload, without the tag.
type VariantElement struct {
Tag uint8
Data []byte
}
// DecodeVariantVector decodes a raw variant vector into tagged raw elements.
// It is useful for higher-level validation of raw transaction fields such as
// extra, attachment, signatures, and proofs.
func DecodeVariantVector(raw []byte) ([]VariantElement, error) {
dec := NewDecoder(bytes.NewReader(raw))
count := dec.ReadVarint()
if dec.Err() != nil {
return nil, dec.Err()
}
elems := make([]VariantElement, 0, int(count))
for i := uint64(0); i < count; i++ {
tag := dec.ReadUint8()
if dec.Err() != nil {
return nil, coreerr.E("DecodeVariantVector", fmt.Sprintf("read tag %d", i), dec.Err())
}
data := readVariantElementData(dec, tag)
if dec.Err() != nil {
return nil, coreerr.E("DecodeVariantVector", fmt.Sprintf("read element %d", i), dec.Err())
}
elems = append(elems, VariantElement{Tag: tag, Data: data})
}
return elems, nil
}
// DecodeAssetDescriptorOperation decodes a raw asset_descriptor_operation
// payload into its typed representation.
func DecodeAssetDescriptorOperation(raw []byte) (types.AssetDescriptorOperation, error) {
dec := NewDecoder(bytes.NewReader(raw))
var op types.AssetDescriptorOperation
op.Version = dec.ReadUint8()
op.OperationType = dec.ReadUint8()
if dec.ReadUint8() != 0 {
assetID := dec.ReadBytes(32)
if dec.Err() != nil {
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "read asset id", dec.Err())
}
copy(op.AssetID[:], assetID)
}
if dec.ReadUint8() != 0 {
desc := &types.AssetDescriptorBase{}
desc.Ticker = decodeStringField(dec)
desc.FullName = decodeStringField(dec)
desc.TotalMaxSupply = dec.ReadUint64LE()
desc.CurrentSupply = dec.ReadUint64LE()
desc.DecimalPoint = dec.ReadUint8()
desc.MetaInfo = decodeStringField(dec)
ownerKey := dec.ReadBytes(32)
if dec.Err() != nil {
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "read owner key", dec.Err())
}
copy(desc.OwnerKey[:], ownerKey)
desc.Etc = readVariantVectorFixed(dec, 1)
if dec.Err() != nil {
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "read descriptor etc", dec.Err())
}
op.Descriptor = desc
}
op.AmountToEmit = dec.ReadUint64LE()
op.AmountToBurn = dec.ReadUint64LE()
op.Etc = readVariantVectorFixed(dec, 1)
if dec.Err() != nil {
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "read trailing etc", dec.Err())
}
if dec.Err() != nil {
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "decode asset descriptor operation", dec.Err())
}
return op, nil
}