ChainSafe / ChainSafe/gossamer
Task: Implement `Compact<u32>` for Marshaling assetID in ChainSafe Gossamer (Golang)
- Dominant language
- Go
- Stars
- 454
- Forks
- 144
- PR merge metrics
- No merged PRs in 30d
Description
### Task: Implement `Compact` 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
- go version: go1.24.4 darwin/arm64
- gossamer version: 0.9.0
- operating system: macos-15.6
- additional links: https://docs.rs/parity-scale-codec/latest/src/parity_scale_codec/compact.rs.html#331
#### 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 🙏**
Contributor guide
Assessment
This issue has not been assessed yet.