2026-04-04 20:14:54 +00:00
|
|
|
// 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))
|
2026-04-04 23:09:26 +00:00
|
|
|
_, 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
|
2026-04-04 20:14:54 +00:00
|
|
|
var op types.AssetDescriptorOperation
|
|
|
|
|
|
2026-04-04 23:09:26 +00:00
|
|
|
appendByte := func(v uint8) {
|
|
|
|
|
raw = append(raw, v)
|
|
|
|
|
}
|
|
|
|
|
appendBytes := func(v []byte) {
|
|
|
|
|
raw = append(raw, v...)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
op.Version = dec.ReadUint8()
|
2026-04-04 23:09:26 +00:00
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendByte(op.Version)
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
op.OperationType = dec.ReadUint8()
|
2026-04-04 23:09:26 +00:00
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendByte(op.OperationType)
|
2026-04-04 20:14:54 +00:00
|
|
|
|
2026-04-04 23:09:26 +00:00
|
|
|
assetMarker := dec.ReadUint8()
|
|
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendByte(assetMarker)
|
|
|
|
|
if assetMarker != 0 {
|
2026-04-04 20:14:54 +00:00
|
|
|
assetID := dec.ReadBytes(32)
|
|
|
|
|
if dec.Err() != nil {
|
2026-04-04 23:09:26 +00:00
|
|
|
return nil, types.AssetDescriptorOperation{}
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|
|
|
|
|
copy(op.AssetID[:], assetID)
|
2026-04-04 23:09:26 +00:00
|
|
|
appendBytes(assetID)
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-04 23:09:26 +00:00
|
|
|
descMarker := dec.ReadUint8()
|
|
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendByte(descMarker)
|
|
|
|
|
if descMarker != 0 {
|
2026-04-04 20:14:54 +00:00
|
|
|
desc := &types.AssetDescriptorBase{}
|
2026-04-04 23:09:26 +00:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
desc.TotalMaxSupply = dec.ReadUint64LE()
|
2026-04-04 23:09:26 +00:00
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendBytes(uint64LEBytes(desc.TotalMaxSupply))
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
desc.CurrentSupply = dec.ReadUint64LE()
|
2026-04-04 23:09:26 +00:00
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendBytes(uint64LEBytes(desc.CurrentSupply))
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
desc.DecimalPoint = dec.ReadUint8()
|
2026-04-04 23:09:26 +00:00
|
|
|
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)
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
ownerKey := dec.ReadBytes(32)
|
|
|
|
|
if dec.Err() != nil {
|
2026-04-04 23:09:26 +00:00
|
|
|
return nil, types.AssetDescriptorOperation{}
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|
|
|
|
|
copy(desc.OwnerKey[:], ownerKey)
|
2026-04-04 23:09:26 +00:00
|
|
|
appendBytes(ownerKey)
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
desc.Etc = readVariantVectorFixed(dec, 1)
|
|
|
|
|
if dec.Err() != nil {
|
2026-04-04 23:09:26 +00:00
|
|
|
return nil, types.AssetDescriptorOperation{}
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|
2026-04-04 23:09:26 +00:00
|
|
|
appendBytes(desc.Etc)
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
op.Descriptor = desc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
op.AmountToEmit = dec.ReadUint64LE()
|
2026-04-04 23:09:26 +00:00
|
|
|
if dec.Err() != nil {
|
|
|
|
|
return nil, types.AssetDescriptorOperation{}
|
|
|
|
|
}
|
|
|
|
|
appendBytes(uint64LEBytes(op.AmountToEmit))
|
|
|
|
|
|
2026-04-04 20:14:54 +00:00
|
|
|
op.AmountToBurn = dec.ReadUint64LE()
|
|
|
|
|
if dec.Err() != nil {
|
2026-04-04 23:09:26 +00:00
|
|
|
return nil, types.AssetDescriptorOperation{}
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|
2026-04-04 23:09:26 +00:00
|
|
|
appendBytes(uint64LEBytes(op.AmountToBurn))
|
2026-04-04 20:14:54 +00:00
|
|
|
|
2026-04-04 23:09:26 +00:00
|
|
|
op.Etc = readVariantVectorFixed(dec, 1)
|
2026-04-04 20:14:54 +00:00
|
|
|
if dec.Err() != nil {
|
2026-04-04 23:09:26 +00:00
|
|
|
return nil, types.AssetDescriptorOperation{}
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|
2026-04-04 23:09:26 +00:00
|
|
|
appendBytes(op.Etc)
|
2026-04-04 20:14:54 +00:00
|
|
|
|
2026-04-04 23:09:26 +00:00
|
|
|
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),
|
|
|
|
|
}
|
2026-04-04 20:14:54 +00:00
|
|
|
}
|