Skip to content

Commit 853c727

Browse files
mattac21maxim-inj
authored andcommitted
Merge commit from fork
* add VaidateBasic to BitArray to ensure Bits and len(Elems) are valid * call ValidateBasic on BitArrays when receiving as a msg from exteranl nodes * enfore SetIndex is not setting out of bounds * add guard to getNumTrueIndices getNumTrueIndices will index out of bounds if Bits and Elems have a mismatch where len(elems) != (bits+63)/64, this guard makes it simply return 0 if this mismatch is present * changelog * fix missing import for v0.38.x * update changelog for release of v0.38.19 * remove duplicate bug fixes from unreleased * fix changelog date * fix lint * fix expected error string in test
1 parent 1615241 commit 853c727

File tree

5 files changed

+141
-34
lines changed

5 files changed

+141
-34
lines changed

CHANGELOG.md

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ team, including:
5858
details.
5959
5. The first officially supported release of the [data companion
6060
API](./docs/architecture/adr-101-data-companion-pull-api.md).
61-
6. Versioning of both the Protobuf definitions _and_ RPC. By versioning our
61+
6. Versioning of both the Protobuf definitions *and* RPC. By versioning our
6262
APIs, we aim to provide a level of commitment to API stability while
6363
simultaneously affording ourselves the ability to roll out substantial
6464
changes in non-breaking releases of CometBFT. See [ADR
@@ -88,7 +88,7 @@ the stability guarantees we provide for pre-releases.
8888

8989
### BREAKING CHANGES
9090

91-
- `[abci/types]` Rename `UpdateValidator` to `NewValidatorUpdate`, remove
91+
- `[abci/types]` Rename `UpdateValidator` to `NewValidatorUpdate`, remove
9292
`Ed25519ValidatorUpdate` ([\#2843](https://github.com/cometbft/cometbft/pull/2843))
9393
- [`config`] deprecate boltdb and cleveldb. If you're using either of those,
9494
please reach out ([\#2775](https://github.com/cometbft/cometbft/pull/2775))
@@ -114,12 +114,12 @@ method is removed ([\#4040](https://github.com/cometbft/cometbft/pull/4040)).
114114
instances to follow the naming changes in the proto-derived
115115
`api/cometbft/abci/v1` package
116116
([\#1533](https://github.com/cometbft/cometbft/pull/1533)):
117-
* The prefixed naming pattern `RequestFoo`, `ReponseFoo` changed to
117+
- The prefixed naming pattern `RequestFoo`, `ReponseFoo` changed to
118118
suffixed `FooRequest`, `FooResponse`.
119-
* Each method gets its own unique request and response type to allow for
119+
- Each method gets its own unique request and response type to allow for
120120
independent evolution with backward compatibility.
121-
* `ABCIClient` renamed to `ABCIServiceClient`.
122-
* `ABCIServer` renamed to `ABCIServiceServer`.
121+
- `ABCIClient` renamed to `ABCIServiceClient`.
122+
- `ABCIServer` renamed to `ABCIServiceServer`.
123123
- `[blocksync]` Move to `internal`
124124
([\#1485](https://github.com/cometbft/cometbft/pull/1485))
125125
- `[cmd]` Remove `replay` and `replay-console` subcommands
@@ -232,14 +232,14 @@ method is removed ([\#4040](https://github.com/cometbft/cometbft/pull/4040)).
232232
data companion gRPC API as per
233233
[RFC 106](https://github.com/cometbft/cometbft/blob/main/docs/references/rfc/rfc-106-separate-stateful-methods.md)
234234
([\#2230](https://github.com/cometbft/cometbft/issues/2230)):
235-
* `GetLatest` from `cometbft.services.block.v1.BlockService`;
236-
* `GetLatestBlockResults` from `cometbft.services.block_results.v1.BlockResultsService`.
235+
- `GetLatest` from `cometbft.services.block.v1.BlockService`;
236+
- `GetLatestBlockResults` from `cometbft.services.block_results.v1.BlockResultsService`.
237237
- `[rpc/grpc]` Remove support for stateful block data retrieval methods from the
238238
data companion APIs as per [RFC 106](https://github.com/cometbft/cometbft/blob/main/docs/references/rfc/rfc-106-separate-stateful-methods.md)
239-
* `GetLatestBlock` method removed from the `BlockServiceClient` interface.
240-
* `GetLatestBlockResults` method removed from the `BlockResultServiceClient` interface.
241-
* `GetLatest` endpoint is no longer served by `BlockServiceServer` instances.
242-
* `GetLatestBlockResults` endpoint is no longer served by `BlockResultServiceServer` instances.
239+
- `GetLatestBlock` method removed from the `BlockServiceClient` interface.
240+
- `GetLatestBlockResults` method removed from the `BlockResultServiceClient` interface.
241+
- `GetLatest` endpoint is no longer served by `BlockServiceServer` instances.
242+
- `GetLatestBlockResults` endpoint is no longer served by `BlockResultServiceServer` instances.
243243
- `[proto]` Renamed the packages from `tendermint.*` to `cometbft.*`
244244
and introduced versioned packages to distinguish between proto definitions
245245
released in `0.34.x`, `0.37.x`, `0.38.x`, and `1.x` versions.
@@ -256,26 +256,26 @@ method is removed ([\#4040](https://github.com/cometbft/cometbft/pull/4040)).
256256
([#736](https://github.com/cometbft/cometbft/issues/736),
257257
[#1504](https://github.com/cometbft/cometbft/issues/1504),
258258
[#1530](https://github.com/cometbft/cometbft/issues/1530)):
259-
* Names of request and response types used in gRPC changed by making
259+
- Names of request and response types used in gRPC changed by making
260260
`Request`/`Response` the suffix instead of the prefix, e.g.
261261
`RequestCheckTx``CheckTxRequest`.
262-
* The `Request` and `Response` multiplex messages are redefined accordingly.
263-
* `CheckTxType` values renamed with the `CHECK_TX_TYPE_` prefix.
264-
* `MisbehaviorType` values renamed with the `MISBEHAVIOR_TYPE_` prefix.
265-
* `Result` enum formerly nested in `ResponseOfferSnapshot` replaced with the package-level
262+
- The `Request` and `Response` multiplex messages are redefined accordingly.
263+
- `CheckTxType` values renamed with the `CHECK_TX_TYPE_` prefix.
264+
- `MisbehaviorType` values renamed with the `MISBEHAVIOR_TYPE_` prefix.
265+
- `Result` enum formerly nested in `ResponseOfferSnapshot` replaced with the package-level
266266
`OfferSnapshotResult`, its values named with the
267267
`OFFER_SNAPSHOT_RESULT_` prefix.
268-
* `Result` enum formerly nested in `ResponseApplyShapshotChunk` replaced with the package-level
268+
- `Result` enum formerly nested in `ResponseApplyShapshotChunk` replaced with the package-level
269269
`ApplySnapshotChunkResult`, its values named with the
270270
`APPLY_SNAPSHOT_CHUNK_RESULT_` prefix.
271-
* `Status` enum formerly nested in `ResponseProcessProposal` replaced with the package-level
271+
- `Status` enum formerly nested in `ResponseProcessProposal` replaced with the package-level
272272
`ProcessProposalStatus`, its values named with the
273273
`PROCESS_PROPOSAL_STATUS_` prefix.
274-
* `Status` enum formerly nested in `ResponseVerifyVoteExtension` replaced with the package-level
274+
- `Status` enum formerly nested in `ResponseVerifyVoteExtension` replaced with the package-level
275275
`VerifyVoteExtensionStatus`, its values named with the
276276
`VERIFY_VOTE_EXTENSION_STATUS_` prefix.
277-
* New definition of `Misbehavior` using the changed `MisbehaviorType`.
278-
* The gRPC service is renamed `ABCIService` and defined using the types listed above.
277+
- New definition of `Misbehavior` using the changed `MisbehaviorType`.
278+
- The gRPC service is renamed `ABCIService` and defined using the types listed above.
279279
- `[proto]` In the `cometbft.state.v1` package, the definition for `ABCIResponsesInfo`
280280
is changed, renaming `response_finalize_block` field to `finalize_block`.
281281
- `[proxy]` Expand `ClientCreator` interface to allow
@@ -422,7 +422,7 @@ on the `/block_results` RPC endpoint.
422422

423423
### FEATURES
424424

425-
- `[indexer]` Introduces configurable table names for the PSQL indexer.
425+
- `[indexer]` Introduces configurable table names for the PSQL indexer.
426426
([\#3593](https://github.com/cometbft/cometbft/issues/3593))
427427
- `[config]` Add [`pebbledb`](https://github.com/cockroachdb/pebble). To use, build with
428428
`pebbledb` tag (`go build -tags pebbledb`) ([\#2132](https://github.com/cometbft/cometbft/pull/2132/))
@@ -489,6 +489,7 @@ on the `/block_results` RPC endpoint.
489489
([\#1094](https://github.com/cometbft/cometbft/issues/1094))
490490
- `[light/store]` Added support for a different DB key representation within the light block store ([\#2327](https://github.com/cometbft/cometbft/pull/2327/))
491491
- `[mempool]` Add `nop` mempool ([\#1643](https://github.com/cometbft/cometbft/pull/1643)). If you want to use it, change mempool's `type` to `nop`:
492+
492493
```toml
493494
[mempool]
494495

@@ -502,13 +503,14 @@ on the `/block_results` RPC endpoint.
502503
# is not supported.
503504
type = "nop"
504505
```
506+
505507
- `[metrics]` Add metric for mempool size in bytes `SizeBytes`.
506508
([\#1512](https://github.com/cometbft/cometbft/pull/1512))
507509
- `[metrics]` Add metrics to monitor pruning and current available data in stores: `PruningServiceBlockRetainHeight`, `PruningServiceBlockResultsRetainHeight`, `ApplicationBlockRetainHeight`, `BlockStoreBaseHeight`, `ABCIResultsBaseHeight`.
508510
([\#1234](https://github.com/cometbft/cometbft/pull/1234))
509511
- `[metrics]` Added metrics to monitor block store access. ([\#1974](https://github.com/cometbft/cometbft/pull/1974))
510512
- `[metrics]` Added metrics to monitor state store access. ([\#1974](https://github.com/cometbft/cometbft/pull/1974))
511-
- `[privval]` Add `key-type` flag to all command that _may_ generate a `privval` file,
513+
- `[privval]` Add `key-type` flag to all command that *may* generate a `privval` file,
512514
and make `GenFilePV` flexible to accept different key generators.
513515
([\#3517](https://github.com/cometbft/cometbft/pull/3517))
514516
- `[proto]` Add definitions and generated code for
@@ -809,7 +811,7 @@ synchronous event bus subscription.
809811
This release includes the second part of ABCI++, called ABCI 2.0.
810812
ABCI 2.0 introduces ABCI methods `ExtendVote` and `VerifyVoteExtension`.
811813
These new methods allow the application to add data (opaque to CometBFT),
812-
called _vote extensions_ to precommit votes sent by validators.
814+
called *vote extensions* to precommit votes sent by validators.
813815
These vote extensions are made available to the proposer(s) of the next height.
814816
Additionally, ABCI 2.0 coalesces `BeginBlock`, `DeliverTx`, and `EndBlock`
815817
into one method, `FinalizeBlock`, whose `Request*` and `Response*`
@@ -901,7 +903,7 @@ for people who forked CometBFT and interact directly with the indexers kvstore.
901903
- `[light]` Fixed an edge case where a light client would panic when attempting
902904
to query a node that (1) has started from a non-zero height and (2) does
903905
not yet have any data. The light client will now, correctly, not panic
904-
_and_ keep the node in its list of providers in the same way it would if
906+
*and* keep the node in its list of providers in the same way it would if
905907
it queried a node starting from height zero that does not yet have data
906908
([\#575](https://github.com/cometbft/cometbft/issues/575))
907909
- `[mempool/clist_mempool]` Prevent a transaction to appear twice in the mempool
@@ -1049,7 +1051,7 @@ See below for more details.
10491051
queue is full: retry block request after a timeout
10501052
([\#9518](https://github.com/tendermint/tendermint/pull/9518))
10511053
- `[consensus]` ([\#386](https://github.com/cometbft/cometbft/pull/386)) Short-term fix for the case when `needProofBlock` cannot find previous block meta by defaulting to the creation of a new proof block. (@adizere)
1052-
- Special thanks to the [Vega.xyz](https://vega.xyz/) team, and in particular to Zohar (@ze97286), for reporting the problem and working with us to get to a fix.
1054+
- Special thanks to the [Vega.xyz](https://vega.xyz/) team, and in particular to Zohar (@ze97286), for reporting the problem and working with us to get to a fix.
10531055
- `[consensus]` Fixed a busy loop that happened when sending of a block part failed by sleeping in case of error.
10541056
([\#4](https://github.com/informalsystems/tendermint/pull/4))
10551057
- `[consensus]` fix round number of `enterPropose`
@@ -1142,7 +1144,7 @@ to this release!
11421144
- `[consensus]` Short-term fix for the case when `needProofBlock` cannot find
11431145
previous block meta by defaulting to the creation of a new proof block.
11441146
([\#386](https://github.com/cometbft/cometbft/pull/386): @adizere)
1145-
- Special thanks to the [Vega.xyz](https://vega.xyz/) team, and in particular
1147+
- Special thanks to the [Vega.xyz](https://vega.xyz/) team, and in particular
11461148
to Zohar (@ze97286), for reporting the problem and working with us to get to
11471149
a fix.
11481150
- `[p2p]` Correctly use non-blocking `TrySendEnvelope` method when attempting to
@@ -1168,7 +1170,7 @@ to this release!
11681170
### FEATURES
11691171

11701172
- `[rpc]` Add `match_event` query parameter to indicate to the RPC that it
1171-
should match events _within_ attributes, not only within a height
1173+
should match events *within* attributes, not only within a height
11721174
([tendermint/tendermint\#9759](https://github.com/tendermint/tendermint/pull/9759))
11731175

11741176
### IMPROVEMENTS

internal/bits/bit_array.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func NewBitArray(bits int) *BitArray {
2828
}
2929
return &BitArray{
3030
Bits: bits,
31-
Elems: make([]uint64, (bits+63)/64),
31+
Elems: make([]uint64, numElements(bits)),
3232
}
3333
}
3434

@@ -41,7 +41,7 @@ func NewBitArrayFromFn(bits int, fn func(int) bool) *BitArray {
4141
}
4242
bA := &BitArray{
4343
Bits: bits,
44-
Elems: make([]uint64, (bits+63)/64),
44+
Elems: make([]uint64, numElements(bits)),
4545
}
4646
for i := 0; i < bits; i++ {
4747
v := fn(i)
@@ -90,7 +90,7 @@ func (bA *BitArray) SetIndex(i int, v bool) bool {
9090
}
9191

9292
func (bA *BitArray) setIndex(i int, v bool) bool {
93-
if i >= bA.Bits {
93+
if i >= bA.Bits || i/64 >= len(bA.Elems) {
9494
return false
9595
}
9696
if v {
@@ -121,7 +121,7 @@ func (bA *BitArray) copy() *BitArray {
121121
}
122122

123123
func (bA *BitArray) copyBits(bits int) *BitArray {
124-
c := make([]uint64, (bits+63)/64)
124+
c := make([]uint64, numElements(bits))
125125
copy(c, bA.Elems)
126126
return &BitArray{
127127
Bits: bits,
@@ -282,6 +282,11 @@ func (bA *BitArray) PickRandom(r *rand.Rand) (int, bool) {
282282
}
283283

284284
func (bA *BitArray) getNumTrueIndices() int {
285+
if bA.Size() == 0 || len(bA.Elems) == 0 || len(bA.Elems) != numElements(bA.Size()) {
286+
// size and elements must be valid to do this calc
287+
return 0
288+
}
289+
285290
count := 0
286291
numElems := len(bA.Elems)
287292
// handle all elements except the last one
@@ -500,3 +505,22 @@ func (bA *BitArray) FromProto(protoBitArray *cmtprotobits.BitArray) {
500505
bA.Elems = protoBitArray.Elems
501506
}
502507
}
508+
509+
// ValidateBasic validates a BitArray. Note that a nil BitArray and BitArray of
510+
// size 0 bits is valid. However the number of Bits and Elems be valid based on
511+
// each other.
512+
func (bA *BitArray) ValidateBasic() error {
513+
if bA == nil {
514+
return nil
515+
}
516+
517+
expectedElems := numElements(bA.Size())
518+
if expectedElems != len(bA.Elems) {
519+
return fmt.Errorf("mismatch between specified number of bits %d, and number of elements %d, expected %d elements", bA.Size(), len(bA.Elems), expectedElems)
520+
}
521+
return nil
522+
}
523+
524+
func numElements(bits int) int {
525+
return (bits + 63) / 64
526+
}

internal/bits/bit_array_test.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,28 @@ func TestGetNumTrueIndices(t *testing.T) {
177177
}
178178
}
179179

180+
func TestGetNumTrueIndicesInvalidStates(t *testing.T) {
181+
testCases := []struct {
182+
name string
183+
bA1 *BitArray
184+
exp int
185+
}{
186+
{"empty", &BitArray{}, 0},
187+
{"explicit 0 bits nil elements", &BitArray{Bits: 0, Elems: nil}, 0},
188+
{"explicit 0 bits 0 len elements", &BitArray{Bits: 0, Elems: make([]uint64, 0)}, 0},
189+
{"nil", nil, 0},
190+
{"with elements", NewBitArray(10), 0},
191+
{"more elements than bits specifies", &BitArray{Bits: 0, Elems: make([]uint64, 5)}, 0},
192+
{"less elements than bits specifies", &BitArray{Bits: 200, Elems: make([]uint64, 1)}, 0},
193+
}
194+
for _, tc := range testCases {
195+
t.Run(tc.name, func(t *testing.T) {
196+
n := tc.bA1.getNumTrueIndices()
197+
require.Equal(t, n, tc.exp)
198+
})
199+
}
200+
}
201+
180202
func TestGetNthTrueIndex(t *testing.T) {
181203
type testcase struct {
182204
Input string
@@ -230,7 +252,7 @@ func TestGetNthTrueIndex(t *testing.T) {
230252
}
231253
}
232254

233-
func TestBytes(_ *testing.T) {
255+
func TestBytes(t *testing.T) {
234256
bA := NewBitArray(4)
235257
bA.SetIndex(0, true)
236258
check := func(bA *BitArray, bz []byte) {
@@ -257,6 +279,10 @@ func TestBytes(_ *testing.T) {
257279
check(bA, []byte{0x80, 0x01})
258280
bA.SetIndex(9, true)
259281
check(bA, []byte{0x80, 0x03})
282+
283+
bA = NewBitArray(4)
284+
bA.Elems = nil
285+
require.False(t, bA.SetIndex(1, true))
260286
}
261287

262288
func TestEmptyFull(t *testing.T) {
@@ -374,6 +400,28 @@ func TestBitArrayProtoBuf(t *testing.T) {
374400
}
375401
}
376402

403+
func TestBitArrayValidateBasic(t *testing.T) {
404+
testCases := []struct {
405+
name string
406+
bA1 *BitArray
407+
expPass bool
408+
}{
409+
{"valid empty", &BitArray{}, true},
410+
{"valid explicit 0 bits nil elements", &BitArray{Bits: 0, Elems: nil}, true},
411+
{"valid explicit 0 bits 0 len elements", &BitArray{Bits: 0, Elems: make([]uint64, 0)}, true},
412+
{"valid nil", nil, true},
413+
{"valid with elements", NewBitArray(10), true},
414+
{"more elements than bits specifies", &BitArray{Bits: 0, Elems: make([]uint64, 5)}, false},
415+
{"less elements than bits specifies", &BitArray{Bits: 200, Elems: make([]uint64, 1)}, false},
416+
}
417+
for _, tc := range testCases {
418+
t.Run(tc.name, func(t *testing.T) {
419+
err := tc.bA1.ValidateBasic()
420+
require.Equal(t, err == nil, tc.expPass)
421+
})
422+
}
423+
}
424+
377425
// Tests that UnmarshalJSON doesn't crash when no bits are passed into the JSON.
378426
// See issue https://github.com/cometbft/cometbft/issues/2658
379427
func TestUnmarshalJSONDoesntCrashOnZeroBits(t *testing.T) {

internal/consensus/reactor.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,9 @@ func (m *NewValidBlockMessage) ValidateBasic() error {
17581758
if err := m.BlockPartSetHeader.ValidateBasic(); err != nil {
17591759
return cmterrors.ErrWrongField{Field: "BlockPartSetHeader", Err: err}
17601760
}
1761+
if err := m.BlockParts.ValidateBasic(); err != nil {
1762+
return fmt.Errorf("validating BlockParts: %w", err)
1763+
}
17611764
if m.BlockParts.Size() == 0 {
17621765
return cmterrors.ErrRequiredField{Field: "blockParts"}
17631766
}
@@ -1812,6 +1815,9 @@ func (m *ProposalPOLMessage) ValidateBasic() error {
18121815
if m.ProposalPOLRound < 0 {
18131816
return cmterrors.ErrNegativeField{Field: "ProposalPOLRound"}
18141817
}
1818+
if err := m.ProposalPOL.ValidateBasic(); err != nil {
1819+
return fmt.Errorf("validating ProposalPOL: %w", err)
1820+
}
18151821
if m.ProposalPOL.Size() == 0 {
18161822
return cmterrors.ErrRequiredField{Field: "ProposalPOL"}
18171823
}
@@ -1957,6 +1963,9 @@ func (m *VoteSetBitsMessage) ValidateBasic() error {
19571963
if err := m.BlockID.ValidateBasic(); err != nil {
19581964
return cmterrors.ErrWrongField{Field: "BlockID", Err: err}
19591965
}
1966+
if err := m.Votes.ValidateBasic(); err != nil {
1967+
return fmt.Errorf("validating Votes: %w", err)
1968+
}
19601969
// NOTE: Votes.Size() can be zero if the node does not have any
19611970
if m.Votes.Size() > types.MaxVotesCount {
19621971
return fmt.Errorf("votes bit array is too big: %d, max: %d", m.Votes.Size(), types.MaxVotesCount)

internal/consensus/reactor_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,14 @@ func TestNewValidBlockMessageValidateBasic(t *testing.T) {
882882
func(msg *NewValidBlockMessage) { msg.BlockParts = bits.NewBitArray(int(types.MaxBlockPartsCount) + 1) },
883883
"blockParts bit array size 1602 not equal to BlockPartSetHeader.Total 1",
884884
},
885+
{
886+
func(msg *NewValidBlockMessage) { msg.BlockParts.Elems = nil },
887+
"mismatch between specified number of bits 1, and number of elements 0, expected 1 elements",
888+
},
889+
{
890+
func(msg *NewValidBlockMessage) { msg.BlockParts.Bits = 500 },
891+
"mismatch between specified number of bits 500, and number of elements 1, expected 8 elements",
892+
},
885893
}
886894

887895
for i, tc := range testCases {
@@ -917,6 +925,14 @@ func TestProposalPOLMessageValidateBasic(t *testing.T) {
917925
func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(types.MaxVotesCount + 1) },
918926
"proposalPOL bit array is too big: 10001, max: 10000",
919927
},
928+
{
929+
func(msg *ProposalPOLMessage) { msg.ProposalPOL.Elems = nil },
930+
"mismatch between specified number of bits 1, and number of elements 0, expected 1 elements",
931+
},
932+
{
933+
func(msg *ProposalPOLMessage) { msg.ProposalPOL.Bits = 500 },
934+
"mismatch between specified number of bits 500, and number of elements 1, expected 8 elements",
935+
},
920936
}
921937

922938
for i, tc := range testCases {
@@ -1069,6 +1085,14 @@ func TestVoteSetBitsMessageValidateBasic(t *testing.T) {
10691085
func(msg *VoteSetBitsMessage) { msg.Votes = bits.NewBitArray(types.MaxVotesCount + 1) },
10701086
"votes bit array is too big: 10001, max: 10000",
10711087
},
1088+
{
1089+
func(msg *VoteSetBitsMessage) { msg.Votes.Elems = nil },
1090+
"mismatch between specified number of bits 1, and number of elements 0, expected 1 elements",
1091+
},
1092+
{
1093+
func(msg *VoteSetBitsMessage) { msg.Votes.Bits = 500 },
1094+
"mismatch between specified number of bits 500, and number of elements 1, expected 8 elements",
1095+
},
10721096
}
10731097

10741098
for i, tc := range testCases {

0 commit comments

Comments
 (0)