-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e0fa0d9
commit 2d747f9
Showing
8 changed files
with
435 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright 2023 ChainSafe Systems (ON) | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
package scale | ||
|
||
const ( | ||
// maxLen equivalent of `ARCH32BIT_BITSLICE_MAX_BITS` in parity-scale-codec | ||
maxLen = 268435455 | ||
// byteSize is the number of bits in a byte | ||
byteSize = 8 | ||
) | ||
|
||
// BitVec is the implementation of the bit vector | ||
type BitVec struct { | ||
bits []bool | ||
} | ||
|
||
// NewBitVec returns a new BitVec with the given bits | ||
// This isn't a complete implementation of the bit vector | ||
// It is only used for ParachainHost runtime exports | ||
// TODO: Implement the full bit vector | ||
// https://github.com/ChainSafe/gossamer/issues/3248 | ||
func NewBitVec(bits []bool) BitVec { | ||
return BitVec{ | ||
bits: bits, | ||
} | ||
} | ||
|
||
// Bits returns the bits in the BitVec | ||
func (bv *BitVec) Bits() []bool { | ||
return bv.bits | ||
} | ||
|
||
// Bytes returns the byte representation of the BitVec.Bits | ||
func (bv *BitVec) Bytes() []byte { | ||
return bitsToBytes(bv.bits) | ||
} | ||
|
||
// Size returns the number of bits in the BitVec | ||
func (bv *BitVec) Size() uint { | ||
return uint(len(bv.bits)) | ||
} | ||
|
||
// bitsToBytes converts a slice of bits to a slice of bytes | ||
// Uses lsb ordering | ||
// TODO: Implement msb ordering | ||
// https://github.com/ChainSafe/gossamer/issues/3248 | ||
func bitsToBytes(bits []bool) []byte { | ||
bitLength := len(bits) | ||
numOfBytes := (bitLength + (byteSize - 1)) / byteSize | ||
bytes := make([]byte, numOfBytes) | ||
|
||
if len(bits)%byteSize != 0 { | ||
// Pad with zeros to make the number of bits a multiple of byteSize | ||
pad := make([]bool, byteSize-len(bits)%byteSize) | ||
bits = append(bits, pad...) | ||
} | ||
|
||
for i := 0; i < bitLength; i++ { | ||
if bits[i] { | ||
byteIndex := i / byteSize | ||
bitIndex := i % byteSize | ||
bytes[byteIndex] |= 1 << bitIndex | ||
} | ||
} | ||
|
||
return bytes | ||
} | ||
|
||
// bytesToBits converts a slice of bytes to a slice of bits | ||
func bytesToBits(b []byte, size uint) []bool { | ||
var bits []bool | ||
for _, uint8val := range b { | ||
end := size | ||
if end > byteSize { | ||
end = byteSize | ||
} | ||
size -= end | ||
|
||
for j := uint(0); j < end; j++ { | ||
bit := (uint8val>>j)&1 == 1 | ||
bits = append(bits, bit) | ||
} | ||
} | ||
|
||
return bits | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright 2023 ChainSafe Systems (ON) | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
package scale | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ChainSafe/gossamer/lib/common" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestBitVec(t *testing.T) { | ||
t.Parallel() | ||
tests := []struct { | ||
name string | ||
in string | ||
wantBitVec BitVec | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "empty_bitvec", | ||
in: "0x00", | ||
wantBitVec: NewBitVec(nil), | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1_byte", | ||
in: "0x2055", | ||
wantBitVec: NewBitVec([]bool{true, false, true, false, true, false, true, false}), | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "4_bytes", | ||
in: "0x645536aa01", | ||
wantBitVec: NewBitVec([]bool{ | ||
true, false, true, false, true, false, true, false, | ||
false, true, true, false, true, true, false, false, | ||
false, true, false, true, false, true, false, true, | ||
true, | ||
}), | ||
wantErr: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
resultBytes, err := common.HexToBytes(tt.in) | ||
require.NoError(t, err) | ||
|
||
bv := NewBitVec(nil) | ||
err = Unmarshal(resultBytes, &bv) | ||
require.NoError(t, err) | ||
|
||
require.Equal(t, tt.wantBitVec.Size(), bv.Size()) | ||
require.Equal(t, tt.wantBitVec.Size(), bv.Size()) | ||
|
||
b, err := Marshal(bv) | ||
require.NoError(t, err) | ||
require.Equal(t, resultBytes, b) | ||
}) | ||
} | ||
} | ||
|
||
func TestBitVecBytes(t *testing.T) { | ||
t.Parallel() | ||
tests := []struct { | ||
name string | ||
in BitVec | ||
want []byte | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "empty_bitvec", | ||
in: NewBitVec(nil), | ||
want: []byte(nil), | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1_byte", | ||
in: NewBitVec([]bool{true, false, true, false, true, false, true, false}), | ||
want: []byte{0x55}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "4_bytes", | ||
in: NewBitVec([]bool{ | ||
true, false, true, false, true, false, true, false, | ||
false, true, true, false, true, true, false, false, | ||
false, true, false, true, false, true, false, true, | ||
true, | ||
}), | ||
want: []byte{0x55, 0x36, 0xaa, 0x1}, | ||
wantErr: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
require.Equal(t, tt.want, tt.in.Bytes()) | ||
}) | ||
} | ||
} | ||
|
||
func TestBitVecBytesToBits(t *testing.T) { | ||
t.Parallel() | ||
tests := []struct { | ||
name string | ||
in []byte | ||
want []bool | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "empty", | ||
in: []byte(nil), | ||
want: []bool(nil), | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1_byte", | ||
in: []byte{0x55}, | ||
want: []bool{true, false, true, false, true, false, true, false}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "4_bytes", | ||
in: []byte{0x55, 0x36, 0xaa, 0x1}, | ||
want: []bool{ | ||
true, false, true, false, true, false, true, false, | ||
false, true, true, false, true, true, false, false, | ||
false, true, false, true, false, true, false, true, | ||
true, false, false, false, false, false, false, false, | ||
}, | ||
wantErr: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
require.Equal(t, tt.want, bytesToBits(tt.in, uint(len(tt.in)*byteSize))) | ||
}) | ||
} | ||
} | ||
|
||
func TestBitVecBitsToBytes(t *testing.T) { | ||
t.Parallel() | ||
tests := []struct { | ||
name string | ||
in []bool | ||
want []byte | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "empty", | ||
in: []bool(nil), | ||
want: []byte{}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1_byte", | ||
in: []bool{true, false, true, false, true, false, true, false}, | ||
want: []byte{0x55}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "4_bytes", | ||
in: []bool{ | ||
true, false, true, false, true, false, true, false, | ||
false, true, true, false, true, true, false, false, | ||
false, true, false, true, false, true, false, true, | ||
true, | ||
}, | ||
want: []byte{0x55, 0x36, 0xaa, 0x1}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
require.Equal(t, tt.want, bitsToBytes(tt.in)) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.