Skip to content

Commit 0b8ba91

Browse files
committed
Replace panic with error handling
Starting from the processor.Block.Process all methods now return errors if something goes wrong with unpacking of the blocks and reading the transactions. In each function where the error is being propagated back to client it is wrapped in a message with the function name. This makes it easier to track down the error and see the propagation chain. Finally the error is logged to the terminal and the go routine shuts down gracefully. The graceful shutdown executes all deferred functions which close the context, the checkpointer and the gateway. Before panics were used everywhere which was an issue because the unpacking of the blocks happened in a go routine. When a panic happens in a go routine only the deferred functions of the go routine are called but not those of the client which lead to unexpected behavior. Signed-off-by: Stanislav Jakuschevskij <stas@two-giants.com>
1 parent ed3737d commit 0b8ba91

File tree

13 files changed

+380
-155
lines changed

13 files changed

+380
-155
lines changed

off_chain_data/application-go/listen.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ func listen(clientConnection *grpc.ClientConn) {
8080
channelName,
8181
)
8282

83-
if err := blockProcessor.Process(); err == store.ErrExpected {
84-
fmt.Println(err)
83+
if err := blockProcessor.Process(); err != nil {
84+
fmt.Println("\033[31m[ERROR]\033[0m", err)
8585
return
8686
}
8787
}

off_chain_data/application-go/parser/block.go

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,74 +14,102 @@ type Block struct {
1414
}
1515

1616
func ParseBlock(block *common.Block) *Block {
17-
return &Block{block, nil}
17+
return &Block{block, []*Transaction{}}
1818
}
1919

20-
func (b *Block) Number() uint64 {
21-
header := utils.AssertDefined(b.block.GetHeader(), "missing block header")
22-
return header.GetNumber()
20+
func (b *Block) Number() (uint64, error) {
21+
header, err := utils.AssertDefined(b.block.GetHeader(), "missing block header")
22+
if err != nil {
23+
return 0, fmt.Errorf("in Number: %w", err)
24+
}
25+
return header.GetNumber(), nil
2326
}
2427

25-
func (b *Block) Transactions() []*Transaction {
26-
return utils.Cache(func() []*Transaction {
27-
envelopes := b.unmarshalEnvelopesFromBlockData()
28+
func (b *Block) Transactions() ([]*Transaction, error) {
29+
return utils.Cache(func() ([]*Transaction, error) {
30+
funcName := "Transactions"
31+
envelopes, err := b.unmarshalEnvelopesFromBlockData()
32+
if err != nil {
33+
return nil, fmt.Errorf("in %s: %w", funcName, err)
34+
}
2835

29-
commonPayloads := b.unmarshalPayloadsFrom(envelopes)
36+
commonPayloads, err := b.unmarshalPayloadsFrom(envelopes)
37+
if err != nil {
38+
return nil, fmt.Errorf("in %s: %w", funcName, err)
39+
}
3040

31-
payloads := b.parse(commonPayloads)
41+
payloads, err := b.parse(commonPayloads)
42+
if err != nil {
43+
return nil, fmt.Errorf("in %s: %w", funcName, err)
44+
}
3245

33-
return b.createTransactionsFrom(payloads)
46+
return b.createTransactionsFrom(payloads), nil
3447
})()
3548
}
3649

37-
func (b *Block) unmarshalEnvelopesFromBlockData() []*common.Envelope {
50+
func (b *Block) unmarshalEnvelopesFromBlockData() ([]*common.Envelope, error) {
3851
result := []*common.Envelope{}
3952
for _, blockData := range b.block.GetData().GetData() {
4053
envelope := &common.Envelope{}
4154
if err := proto.Unmarshal(blockData, envelope); err != nil {
42-
panic(err)
55+
return nil, fmt.Errorf("in unmarshalEnvelopesFromBlockData: %w", err)
4356
}
4457
result = append(result, envelope)
4558
}
46-
return result
59+
return result, nil
4760
}
4861

49-
func (*Block) unmarshalPayloadsFrom(envelopes []*common.Envelope) []*common.Payload {
62+
func (*Block) unmarshalPayloadsFrom(envelopes []*common.Envelope) ([]*common.Payload, error) {
5063
result := []*common.Payload{}
5164
for _, envelope := range envelopes {
5265
commonPayload := &common.Payload{}
5366
if err := proto.Unmarshal(envelope.GetPayload(), commonPayload); err != nil {
54-
panic(err)
67+
return nil, fmt.Errorf("in unmarshalPayloadsFrom: %w", err)
5568
}
5669
result = append(result, commonPayload)
5770
}
58-
return result
71+
return result, nil
5972
}
6073

61-
func (b *Block) parse(commonPayloads []*common.Payload) []*payload {
62-
validationCodes := b.extractTransactionValidationCodes()
74+
func (b *Block) parse(commonPayloads []*common.Payload) ([]*payload, error) {
75+
funcName := "parse"
76+
77+
validationCodes, err := b.extractTransactionValidationCodes()
78+
if err != nil {
79+
return nil, fmt.Errorf("in %s: %w", funcName, err)
80+
}
81+
6382
result := []*payload{}
6483
for i, commonPayload := range commonPayloads {
65-
payload := parsePayload(
66-
commonPayload,
67-
int32(utils.AssertDefined(
68-
validationCodes[i],
69-
fmt.Sprint("missing validation code index", i),
70-
),
71-
),
84+
statusCode, err := utils.AssertDefined(
85+
validationCodes[i],
86+
fmt.Sprint("missing validation code index", i),
7287
)
73-
if payload.isEndorserTransaction() {
88+
if err != nil {
89+
return nil, fmt.Errorf("in %s: %w", funcName, err)
90+
}
91+
92+
payload := parsePayload(commonPayload, int32(statusCode))
93+
is, err := payload.isEndorserTransaction()
94+
if err != nil {
95+
return nil, fmt.Errorf("in %s: %w", funcName, err)
96+
}
97+
if is {
7498
result = append(result, payload)
7599
}
76100
}
77-
return result
101+
102+
return result, nil
78103
}
79104

80-
func (b *Block) extractTransactionValidationCodes() []byte {
81-
metadata := utils.AssertDefined(
105+
func (b *Block) extractTransactionValidationCodes() ([]byte, error) {
106+
metadata, err := utils.AssertDefined(
82107
b.block.GetMetadata(),
83108
"missing block metadata",
84109
)
110+
if err != nil {
111+
return nil, fmt.Errorf("in extractTransactionValidationCodes: %w", err)
112+
}
85113

86114
return utils.AssertDefined(
87115
metadata.GetMetadata()[common.BlockMetadataIndex_TRANSACTIONS_FILTER],

off_chain_data/application-go/parser/block_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ func Test_GetReadWriteSetsFromEndorserTransaction(t *testing.T) {
3535
}
3636

3737
parsedEndorserTransaction := parseEndorserTransaction(transaction)
38-
if len(parsedEndorserTransaction.readWriteSets()) != 1 {
39-
t.Fatal("expected 1 ReadWriteSet, got", len(parsedEndorserTransaction.readWriteSets()))
38+
readWriteSets, err := parsedEndorserTransaction.readWriteSets()
39+
if err != nil {
40+
t.Fatal("unexpected error:", err)
41+
}
42+
43+
if len(readWriteSets) != 1 {
44+
t.Fatal("expected 1 ReadWriteSet, got", len(readWriteSets))
4045
}
4146

4247
assertReadWriteSet(
43-
parsedEndorserTransaction.readWriteSets()[0].namespaceReadWriteSets()[0],
48+
readWriteSets[0].namespaceReadWriteSets()[0],
4449
expectedNamespace,
4550
expectedAsset,
4651
t,
@@ -57,7 +62,10 @@ func assertReadWriteSet(
5762
t.Errorf("expected namespace %s, got %s", expectedNamespace, parsedNsRwSet.Namespace())
5863
}
5964

60-
actualKVRWSet := parsedNsRwSet.ReadWriteSet()
65+
actualKVRWSet, err := parsedNsRwSet.ReadWriteSet()
66+
if err != nil {
67+
t.Fatal("unexpected error:", err)
68+
}
6169
if len(actualKVRWSet.Writes) != 1 {
6270
t.Fatal("expected 1 write, got", len(actualKVRWSet.Writes))
6371
}

off_chain_data/application-go/parser/endorserTransaction.go

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package parser
22

33
import (
4+
"fmt"
45
"offChainData/utils"
56

67
"github.com/hyperledger/fabric-protos-go-apiv2/ledger/rwset"
@@ -16,83 +17,104 @@ func parseEndorserTransaction(transaction *peer.Transaction) *endorserTransactio
1617
return &endorserTransaction{transaction}
1718
}
1819

19-
func (p *endorserTransaction) readWriteSets() []*readWriteSet {
20-
return utils.Cache(func() []*readWriteSet {
21-
chaincodeActionPayloads := p.unmarshalChaincodeActionPayloads()
20+
func (p *endorserTransaction) readWriteSets() ([]*readWriteSet, error) {
21+
return utils.Cache(func() ([]*readWriteSet, error) {
22+
funcName := "readWriteSets"
23+
chaincodeActionPayloads, err := p.unmarshalChaincodeActionPayloads()
24+
if err != nil {
25+
return nil, fmt.Errorf("in %s: %w", funcName, err)
26+
}
2227

23-
chaincodeEndorsedActions := p.extractChaincodeEndorsedActionsFrom(chaincodeActionPayloads)
28+
chaincodeEndorsedActions, err := p.extractChaincodeEndorsedActionsFrom(chaincodeActionPayloads)
29+
if err != nil {
30+
return nil, fmt.Errorf("in %s: %w", funcName, err)
31+
}
2432

25-
proposalResponsePayloads := p.unmarshalProposalResponsePayloadsFrom(chaincodeEndorsedActions)
33+
proposalResponsePayloads, err := p.unmarshalProposalResponsePayloadsFrom(chaincodeEndorsedActions)
34+
if err != nil {
35+
return nil, fmt.Errorf("in %s: %w", funcName, err)
36+
}
2637

27-
chaincodeActions := p.unmarshalChaincodeActionsFrom(proposalResponsePayloads)
38+
chaincodeActions, err := p.unmarshalChaincodeActionsFrom(proposalResponsePayloads)
39+
if err != nil {
40+
return nil, fmt.Errorf("in %s: %w", funcName, err)
41+
}
2842

29-
txReadWriteSets := p.unmarshalTxReadWriteSetsFrom(chaincodeActions)
43+
txReadWriteSets, err := p.unmarshalTxReadWriteSetsFrom(chaincodeActions)
44+
if err != nil {
45+
return nil, fmt.Errorf("in %s: %w", funcName, err)
46+
}
3047

31-
return p.parseReadWriteSets(txReadWriteSets)
48+
return p.parseReadWriteSets(txReadWriteSets), nil
3249
})()
3350
}
3451

35-
func (p *endorserTransaction) unmarshalChaincodeActionPayloads() []*peer.ChaincodeActionPayload {
52+
func (p *endorserTransaction) unmarshalChaincodeActionPayloads() ([]*peer.ChaincodeActionPayload, error) {
3653
result := []*peer.ChaincodeActionPayload{}
3754
for _, transactionAction := range p.transaction.GetActions() {
3855
chaincodeActionPayload := &peer.ChaincodeActionPayload{}
3956
if err := proto.Unmarshal(transactionAction.GetPayload(), chaincodeActionPayload); err != nil {
40-
panic(err)
57+
return nil, fmt.Errorf("in unmarshalChaincodeActionPayloads: %w", err)
4158
}
4259

4360
result = append(result, chaincodeActionPayload)
4461
}
45-
return result
62+
return result, nil
4663
}
4764

48-
func (*endorserTransaction) extractChaincodeEndorsedActionsFrom(chaincodeActionPayloads []*peer.ChaincodeActionPayload) []*peer.ChaincodeEndorsedAction {
65+
func (*endorserTransaction) extractChaincodeEndorsedActionsFrom(chaincodeActionPayloads []*peer.ChaincodeActionPayload) ([]*peer.ChaincodeEndorsedAction, error) {
4966
result := []*peer.ChaincodeEndorsedAction{}
5067
for _, payload := range chaincodeActionPayloads {
68+
chaincodeEndorsedAction, err := utils.AssertDefined(
69+
payload.GetAction(),
70+
"missing chaincode endorsed action",
71+
)
72+
if err != nil {
73+
return nil, fmt.Errorf("in extractChaincodeEndorsedActionsFrom: %w", err)
74+
}
75+
5176
result = append(
5277
result,
53-
utils.AssertDefined(
54-
payload.GetAction(),
55-
"missing chaincode endorsed action",
56-
),
78+
chaincodeEndorsedAction,
5779
)
5880
}
59-
return result
81+
return result, nil
6082
}
6183

62-
func (*endorserTransaction) unmarshalProposalResponsePayloadsFrom(chaincodeEndorsedActions []*peer.ChaincodeEndorsedAction) []*peer.ProposalResponsePayload {
84+
func (*endorserTransaction) unmarshalProposalResponsePayloadsFrom(chaincodeEndorsedActions []*peer.ChaincodeEndorsedAction) ([]*peer.ProposalResponsePayload, error) {
6385
result := []*peer.ProposalResponsePayload{}
6486
for _, endorsedAction := range chaincodeEndorsedActions {
6587
proposalResponsePayload := &peer.ProposalResponsePayload{}
6688
if err := proto.Unmarshal(endorsedAction.GetProposalResponsePayload(), proposalResponsePayload); err != nil {
67-
panic(err)
89+
return nil, fmt.Errorf("in unmarshalProposalResponsePayloadsFrom: %w", err)
6890
}
6991
result = append(result, proposalResponsePayload)
7092
}
71-
return result
93+
return result, nil
7294
}
7395

74-
func (*endorserTransaction) unmarshalChaincodeActionsFrom(proposalResponsePayloads []*peer.ProposalResponsePayload) []*peer.ChaincodeAction {
96+
func (*endorserTransaction) unmarshalChaincodeActionsFrom(proposalResponsePayloads []*peer.ProposalResponsePayload) ([]*peer.ChaincodeAction, error) {
7597
result := []*peer.ChaincodeAction{}
7698
for _, proposalResponsePayload := range proposalResponsePayloads {
7799
chaincodeAction := &peer.ChaincodeAction{}
78100
if err := proto.Unmarshal(proposalResponsePayload.GetExtension(), chaincodeAction); err != nil {
79-
panic(err)
101+
return nil, fmt.Errorf("in unmarshalChaincodeActionsFrom: %w", err)
80102
}
81103
result = append(result, chaincodeAction)
82104
}
83-
return result
105+
return result, nil
84106
}
85107

86-
func (*endorserTransaction) unmarshalTxReadWriteSetsFrom(chaincodeActions []*peer.ChaincodeAction) []*rwset.TxReadWriteSet {
108+
func (*endorserTransaction) unmarshalTxReadWriteSetsFrom(chaincodeActions []*peer.ChaincodeAction) ([]*rwset.TxReadWriteSet, error) {
87109
result := []*rwset.TxReadWriteSet{}
88110
for _, chaincodeAction := range chaincodeActions {
89111
txReadWriteSet := &rwset.TxReadWriteSet{}
90112
if err := proto.Unmarshal(chaincodeAction.GetResults(), txReadWriteSet); err != nil {
91-
continue
113+
return nil, fmt.Errorf("in unmarshalTxReadWriteSetsFrom: %w", err)
92114
}
93115
result = append(result, txReadWriteSet)
94116
}
95-
return result
117+
return result, nil
96118
}
97119

98120
func (*endorserTransaction) parseReadWriteSets(txReadWriteSets []*rwset.TxReadWriteSet) []*readWriteSet {

off_chain_data/application-go/parser/namespaceReadWriteSet.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package parser
22

33
import (
4+
"fmt"
45
"offChainData/utils"
56

67
"github.com/hyperledger/fabric-protos-go-apiv2/ledger/rwset"
@@ -20,13 +21,13 @@ func (p *NamespaceReadWriteSet) Namespace() string {
2021
return p.nsReadWriteSet.GetNamespace()
2122
}
2223

23-
func (p *NamespaceReadWriteSet) ReadWriteSet() *kvrwset.KVRWSet {
24-
return utils.Cache(func() *kvrwset.KVRWSet {
24+
func (p *NamespaceReadWriteSet) ReadWriteSet() (*kvrwset.KVRWSet, error) {
25+
return utils.Cache(func() (*kvrwset.KVRWSet, error) {
2526
result := kvrwset.KVRWSet{}
2627
if err := proto.Unmarshal(p.nsReadWriteSet.GetRwset(), &result); err != nil {
27-
panic(err)
28+
return nil, fmt.Errorf("in ReadWriteSet: %w", err)
2829
}
2930

30-
return &result
31+
return &result, nil
3132
})()
3233
}

0 commit comments

Comments
 (0)