refactor(wire): unify HF5 asset operation parsing
Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
330ee2a146
commit
123047bebd
3 changed files with 170 additions and 146 deletions
|
|
@ -1029,113 +1029,7 @@ func readZarcanumSig(dec *Decoder) []byte {
|
|||
// decimal_point(uint8) + meta_info(string) + owner_key(32 bytes) +
|
||||
// etc(vector<uint8>).
|
||||
func readAssetDescriptorOperation(dec *Decoder) []byte {
|
||||
var raw []byte
|
||||
|
||||
// ver: uint8
|
||||
ver := dec.ReadUint8()
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, ver)
|
||||
|
||||
// operation_type: uint8
|
||||
opType := dec.ReadUint8()
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, opType)
|
||||
|
||||
// opt_asset_id: uint8 presence marker + 32 bytes if present
|
||||
assetMarker := dec.ReadUint8()
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, assetMarker)
|
||||
if assetMarker != 0 {
|
||||
b := dec.ReadBytes(32)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, b...)
|
||||
}
|
||||
|
||||
// opt_descriptor: uint8 presence marker + descriptor if present
|
||||
descMarker := dec.ReadUint8()
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, descMarker)
|
||||
if descMarker != 0 {
|
||||
// AssetDescriptorBase
|
||||
// ticker: string
|
||||
s := readStringBlob(dec)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, s...)
|
||||
// full_name: string
|
||||
s = readStringBlob(dec)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, s...)
|
||||
// total_max_supply: uint64 LE
|
||||
b := dec.ReadBytes(8)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, b...)
|
||||
// current_supply: uint64 LE
|
||||
b = dec.ReadBytes(8)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, b...)
|
||||
// decimal_point: uint8
|
||||
dp := dec.ReadUint8()
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, dp)
|
||||
// meta_info: string
|
||||
s = readStringBlob(dec)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, s...)
|
||||
// owner_key: 32 bytes
|
||||
b = dec.ReadBytes(32)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, b...)
|
||||
// etc: vector<uint8>
|
||||
v := readVariantVectorFixed(dec, 1)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, v...)
|
||||
}
|
||||
|
||||
// amount_to_emit: uint64 LE
|
||||
b := dec.ReadBytes(8)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, b...)
|
||||
// amount_to_burn: uint64 LE
|
||||
b = dec.ReadBytes(8)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, b...)
|
||||
// etc: vector<uint8>
|
||||
v := readVariantVectorFixed(dec, 1)
|
||||
if dec.err != nil {
|
||||
return nil
|
||||
}
|
||||
raw = append(raw, v...)
|
||||
|
||||
raw, _ := parseAssetDescriptorOperation(dec)
|
||||
return raw
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,23 @@ func TestReadAssetDescriptorOperationEmit_Good(t *testing.T) {
|
|||
if !bytes.Equal(got, blob) {
|
||||
t.Fatalf("round-trip mismatch: got %d bytes, want %d bytes", len(got), len(blob))
|
||||
}
|
||||
|
||||
op, err := DecodeAssetDescriptorOperation(blob)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeAssetDescriptorOperation (emit) failed: %v", err)
|
||||
}
|
||||
if op.Version != 1 || op.OperationType != 1 {
|
||||
t.Fatalf("unexpected operation header: %+v", op)
|
||||
}
|
||||
if op.Descriptor != nil {
|
||||
t.Fatalf("emit operation should not carry descriptor: %+v", op)
|
||||
}
|
||||
if op.AmountToEmit != 500000 || op.AmountToBurn != 0 {
|
||||
t.Fatalf("unexpected emit amounts: %+v", op)
|
||||
}
|
||||
if op.AssetID[0] != 0xAB || op.AssetID[31] != 0xAB {
|
||||
t.Fatalf("unexpected asset id: %x", op.AssetID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVariantVectorWithTag40_Good(t *testing.T) {
|
||||
|
|
|
|||
191
wire/variant.go
191
wire/variant.go
|
|
@ -53,45 +53,7 @@ func DecodeVariantVector(raw []byte) ([]VariantElement, error) {
|
|||
// 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())
|
||||
}
|
||||
_, op := parseAssetDescriptorOperation(dec)
|
||||
|
||||
if dec.Err() != nil {
|
||||
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "decode asset descriptor operation", dec.Err())
|
||||
|
|
@ -99,3 +61,154 @@ func DecodeAssetDescriptorOperation(raw []byte) (types.AssetDescriptorOperation,
|
|||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue