• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperledger / fabric-x-committer / 26212692047

21 May 2026 07:44AM UTC coverage: 91.834% (+0.3%) from 91.503%
26212692047

Pull #605

github

cendhu
Fix numWaitingTxsForStatus not counting rejected transactions

Problem:
The coordinator numWaitingTxsForStatus counter only incremented by
len(blk.Txs), ignoring len(blk.Rejected). When a block contained
rejected transactions, the counter was never decremented back to zero
because sendTxStatus decrements by the actual number of statuses
returned (which includes rejected txs). This caused the waiting
transaction count to go negative, breaking the
NumberOfWaitingTransactionsForStatus API and any callers that rely on
it to determine when all transactions have been processed.

Root cause:
In receiveAndProcessBlock, the counter increment only used len(blk.Txs)
without len(blk.Rejected), despite the metrics counter on the line
above correctly including both via len(blk.Txs)+len(blk.Rejected).

Fix:
Change numWaitingTxsForStatus to add len(blk.Txs) + len(blk.Rejected),
matching the metrics and ensuring the counter is correctly decremented
to zero when all transaction statuses (including rejected) are sent
back to the sidecar.

Added TestWaitingTxsCountReturnsToZeroForBlockWithRejectedTxs to
verify the counter returns to zero after processing a block that
contains both normal and rejected transactions.

Signed-off-by: Senthilnathan <cendhu@gmail.com>
Pull Request #605: [coordinator] Fix numWaitingTxsForStatus not counting rejected transactions

1 of 1 new or added line in 1 file covered. (100.0%)

822 existing lines in 48 files now uncovered.

10256 of 11168 relevant lines covered (91.83%)

82267.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.74
/utils/encoding.go
1
/*
2
Copyright IBM Corp. All Rights Reserved.
3

4
SPDX-License-Identifier: Apache-2.0
5
*/
6

7
package utils
8

9
import (
10
        "encoding/binary"
11
        "fmt"
12

13
        "github.com/cockroachdb/errors"
14
        "github.com/golang/protobuf/proto" //nolint:staticcheck // proto.EncodeVarint does not exist in the new version
15
)
16

17
// EncodeOrderPreservingVarUint64 returns a byte-representation for a uint64 number such that
18
// all zero-bits starting bytes are trimmed in order to reduce the length of the array
19
// For preserving the order in a default bytes-comparison, first byte contains the number of remaining bytes.
20
// The presence of first byte also allows to use the returned bytes as part of other larger byte array such as a
21
// composite-key representation in db.
22
func EncodeOrderPreservingVarUint64(number uint64) []byte {
79,936✔
23
        bytes := make([]byte, 8)
79,936✔
24
        binary.BigEndian.PutUint64(bytes, number)
79,936✔
25
        startingIndex := 0
79,936✔
26
        size := 0
79,936✔
27
        for i, b := range bytes {
685,007✔
28
                if b != 0x00 {
684,703✔
29
                        startingIndex = i
79,632✔
30
                        size = 8 - i
79,632✔
31
                        break
79,632✔
32
                }
33
        }
34

35
        sizeBytes := proto.EncodeVarint(uint64(size)) //nolint:gosec // integer overflow conversion int -> uint64.
79,936✔
36
        if len(sizeBytes) > 1 {
79,936✔
37
                panic(fmt.Errorf(
×
38
                        "[]sizeBytes should not be more than one byte because the max number it needs to hold is 8. size=%d",
×
39
                        size,
×
40
                ))
×
41
        }
42
        encodedBytes := make([]byte, size+1)
79,936✔
43
        encodedBytes[0] = sizeBytes[0]
79,936✔
44
        copy(encodedBytes[1:], bytes[startingIndex:])
79,936✔
45
        return encodedBytes
79,936✔
46
}
47

48
// DecodeOrderPreservingVarUint64 decodes the number from the bytes obtained from method
49
// 'EncodeOrderPreservingVarUint64'.
50
// It returns the decoded number, the number of bytes that are consumed in the process,
51
// and an error if the input bytes are invalid.
52
func DecodeOrderPreservingVarUint64(bytes []byte) (uint64, int, error) {
11,676✔
53
        s, numBytes := proto.DecodeVarint(bytes)
11,676✔
54

11,676✔
55
        switch {
11,676✔
UNCOV
56
        case numBytes != 1:
6✔
UNCOV
57
                return 0, 0, errors.Newf("number of consumed bytes from DecodeVarint is invalid, expected 1, but got %d",
6✔
UNCOV
58
                        numBytes)
6✔
UNCOV
59
        case s > 8:
1✔
UNCOV
60
                return 0, 0, errors.Newf("decoded size from DecodeVarint is invalid, expected <=8, but got %d", s)
1✔
UNCOV
61
        case int(s) > len(bytes)-1:
1✔
UNCOV
62
                return 0, 0, errors.Newf("decoded size (%d) from DecodeVarint is more than available bytes (%d)",
1✔
UNCOV
63
                        s, len(bytes)-1)
1✔
64
        default:
11,668✔
65
                // no error
11,668✔
66
                size := int(s)
11,668✔
67
                decodedBytes := make([]byte, 8)
11,668✔
68
                copy(decodedBytes[8-size:], bytes[1:size+1])
11,668✔
69
                numBytesConsumed := size + 1
11,668✔
70
                return binary.BigEndian.Uint64(decodedBytes), numBytesConsumed, nil
11,668✔
71
        }
72
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc