Skip to content

Task: Implement Compact<u32> for Marshaling assetID in ChainSafe Gossamer (Golang) #4820

Description

@maverick-OO7

Task: Implement Compact<u32> for Marshaling assetID in assets.Transfer method of polkadot in ChainSafe Gossamer (Golang)

Bug Summary

  • The current Gossamer implementation does not correctly marshal substrate Compact types required for assetID, which causes interoperability while decoding when dealing with Polkadot/Substrate protocol messages.

When scale marshaling assetId -> 31337 uint32 result is [105,122,0,0] 0x697a0000 this results in 7,834 when decoded using polkadot js library
However the polkadot protocol expects assetId as Compact which is currently not implemented in Gossammer
assetId -> 31337 CompactU32 result should be [166 233 1 0] -> 0xa6e90100

Expected Behavior

  • Support for Compact encoding should follow the [[SCALE codec specification]
    https://docs.rs/parity-scale-codec/latest/src/parity_scale_codec/compact.rs.html#331

Current Behavior

  • the implementation is missing, resulting in wrong payloads.
  • Decoded assetID values does not match what is expected by Rust-based nodes.

Possible Solution

type CompactU32 uint32

func encodeCompactU32(val CompactU32) []byte {
	switch {
	case val <= 0b0011_1111: // 6 bits
		// 1 byte: [value (6 bits) << 2] + mode 00 (last 2 bits)
		// So just shift val by 2 to left, mode bits are 00 so no OR needed.
		return []byte{byte(val << 2)}

	case val <= 0b0011_1111_1111_1111: // 14 bits
		// 2 bytes: [value (14 bits) << 2] + mode 01
		// Pack into uint16 and encode little endian
		v := uint16(val)<<2 | 0b01
		buf := make([]byte, 2)
		binary.LittleEndian.PutUint16(buf, v)
		return buf

	case val <= 0b0011_1111_1111_1111_1111_1111_1111_1111: // 30 bits
		// 4 bytes: [value (30 bits) << 2] + mode 10
		v := val<<2 | 0b10
		buf := make([]byte, 4)
		binary.LittleEndian.PutUint32(buf, uint32(v))
		return buf

	default:
		// 5 bytes: 1 byte mode 11 + 4 bytes original value
		buf := make([]byte, 5)
		buf[0] = 0b11
		binary.LittleEndian.PutUint32(buf[1:], uint32(val))
		return buf
	}
}

in marshal function
add a case
	case CompactU32:
		err = es.encodeCompactU32(in)

To Reproduce

  1. Attempt to marsha assetID using uint32 implementation in Gossamer for asset.Transfer method.

Log Output

Log Output

paste log output...

Specification

Acceptance Criteria

  • Bug was recreated in deterministic manner.
  • Unit test that covers the problem.
  • Regression test done.
  • Bug is not reproducible anymore.

Implementation Task

Thank you 🙏

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-bugthis issue covers unexpected and/or wrong behaviour.

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions