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) +
|
// decimal_point(uint8) + meta_info(string) + owner_key(32 bytes) +
|
||||||
// etc(vector<uint8>).
|
// etc(vector<uint8>).
|
||||||
func readAssetDescriptorOperation(dec *Decoder) []byte {
|
func readAssetDescriptorOperation(dec *Decoder) []byte {
|
||||||
var raw []byte
|
raw, _ := parseAssetDescriptorOperation(dec)
|
||||||
|
|
||||||
// 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...)
|
|
||||||
|
|
||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,23 @@ func TestReadAssetDescriptorOperationEmit_Good(t *testing.T) {
|
||||||
if !bytes.Equal(got, blob) {
|
if !bytes.Equal(got, blob) {
|
||||||
t.Fatalf("round-trip mismatch: got %d bytes, want %d bytes", len(got), len(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) {
|
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.
|
// payload into its typed representation.
|
||||||
func DecodeAssetDescriptorOperation(raw []byte) (types.AssetDescriptorOperation, error) {
|
func DecodeAssetDescriptorOperation(raw []byte) (types.AssetDescriptorOperation, error) {
|
||||||
dec := NewDecoder(bytes.NewReader(raw))
|
dec := NewDecoder(bytes.NewReader(raw))
|
||||||
var op types.AssetDescriptorOperation
|
_, op := parseAssetDescriptorOperation(dec)
|
||||||
|
|
||||||
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 {
|
if dec.Err() != nil {
|
||||||
return types.AssetDescriptorOperation{}, coreerr.E("DecodeAssetDescriptorOperation", "decode asset descriptor operation", dec.Err())
|
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
|
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