go-blockchain/wire/variant.go

215 lines
5.1 KiB
Go
Raw Normal View History

// 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))
_, op := parseAssetDescriptorOperation(dec)
if dec.Err() != nil {
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "decode asset descriptor operation", dec.Err())
}
return op, nil
}
// parseAssetDescriptorOperation is the single source of truth for both raw
// wire preservation and typed HF5 asset operation decoding.
func parseAssetDescriptorOperation(dec *Decoder) ([]byte, types.AssetDescriptorOperation) {
var raw []byte
var op types.AssetDescriptorOperation
appendByte := func(v uint8) {
raw = append(raw, v)
}
appendBytes := func(v []byte) {
raw = append(raw, v...)
}
op.Version = dec.ReadUint8()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendByte(op.Version)
op.OperationType = dec.ReadUint8()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendByte(op.OperationType)
assetMarker := dec.ReadUint8()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendByte(assetMarker)
if assetMarker != 0 {
assetID := dec.ReadBytes(32)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
copy(op.AssetID[:], assetID)
appendBytes(assetID)
}
descMarker := dec.ReadUint8()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendByte(descMarker)
if descMarker != 0 {
desc := &types.AssetDescriptorBase{}
tickerRaw := readStringBlob(dec)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
desc.Ticker = decodeStringBlob(tickerRaw)
appendBytes(tickerRaw)
fullNameRaw := readStringBlob(dec)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
desc.FullName = decodeStringBlob(fullNameRaw)
appendBytes(fullNameRaw)
desc.TotalMaxSupply = dec.ReadUint64LE()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendBytes(uint64LEBytes(desc.TotalMaxSupply))
desc.CurrentSupply = dec.ReadUint64LE()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendBytes(uint64LEBytes(desc.CurrentSupply))
desc.DecimalPoint = dec.ReadUint8()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendByte(desc.DecimalPoint)
metaInfoRaw := readStringBlob(dec)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
desc.MetaInfo = decodeStringBlob(metaInfoRaw)
appendBytes(metaInfoRaw)
ownerKey := dec.ReadBytes(32)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
copy(desc.OwnerKey[:], ownerKey)
appendBytes(ownerKey)
desc.Etc = readVariantVectorFixed(dec, 1)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendBytes(desc.Etc)
op.Descriptor = desc
}
op.AmountToEmit = dec.ReadUint64LE()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendBytes(uint64LEBytes(op.AmountToEmit))
op.AmountToBurn = dec.ReadUint64LE()
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendBytes(uint64LEBytes(op.AmountToBurn))
op.Etc = readVariantVectorFixed(dec, 1)
if dec.Err() != nil {
return nil, types.AssetDescriptorOperation{}
}
appendBytes(op.Etc)
return raw, op
}
func decodeStringBlob(raw []byte) string {
return string(raw[varintPrefixLen(raw):])
}
func varintPrefixLen(raw []byte) int {
n := 0
for n < len(raw) {
n++
if raw[n-1] < 0x80 {
return n
}
}
return len(raw)
}
func uint64LEBytes(v uint64) []byte {
return []byte{
byte(v),
byte(v >> 8),
byte(v >> 16),
byte(v >> 24),
byte(v >> 32),
byte(v >> 40),
byte(v >> 48),
byte(v >> 56),
}
}