Skip to content

Commit f9285d5

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. The transact function is also executed in a go routine therefore the same typo of error handling was implemented there. Signed-off-by: Stanislav Jakuschevskij <stas@two-giants.com>
1 parent ed3737d commit f9285d5

File tree

16 files changed

+422
-172
lines changed

16 files changed

+422
-172
lines changed

off_chain_data/application-go/contract/contract.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package contract
77

88
import (
9+
"fmt"
910
"strconv"
1011

1112
"github.com/hyperledger/fabric-gateway/pkg/client"
@@ -19,7 +20,7 @@ func NewAssetTransferBasic(contract *client.Contract) *AssetTransferBasic {
1920
return &AssetTransferBasic{contract}
2021
}
2122

22-
func (atb *AssetTransferBasic) CreateAsset(anAsset Asset) {
23+
func (atb *AssetTransferBasic) CreateAsset(anAsset Asset) error {
2324
if _, err := atb.contract.Submit(
2425
"CreateAsset",
2526
client.WithArguments(
@@ -29,11 +30,12 @@ func (atb *AssetTransferBasic) CreateAsset(anAsset Asset) {
2930
anAsset.Owner,
3031
strconv.FormatUint(anAsset.AppraisedValue, 10),
3132
)); err != nil {
32-
panic(err)
33+
return fmt.Errorf("in CreateAsset: %w", err)
3334
}
35+
return nil
3436
}
3537

36-
func (atb *AssetTransferBasic) TransferAsset(id, newOwner string) string {
38+
func (atb *AssetTransferBasic) TransferAsset(id, newOwner string) (string, error) {
3739
result, err := atb.contract.Submit(
3840
"TransferAsset",
3941
client.WithArguments(
@@ -42,27 +44,28 @@ func (atb *AssetTransferBasic) TransferAsset(id, newOwner string) string {
4244
),
4345
)
4446
if err != nil {
45-
panic(err)
47+
return "", fmt.Errorf("in TransferAsset: %w", err)
4648
}
4749

48-
return string(result)
50+
return string(result), nil
4951
}
5052

51-
func (atb *AssetTransferBasic) DeleteAsset(id string) {
53+
func (atb *AssetTransferBasic) DeleteAsset(id string) error {
5254
if _, err := atb.contract.Submit(
5355
"DeleteAsset",
5456
client.WithArguments(
5557
id,
5658
),
5759
); err != nil {
58-
panic(err)
60+
return fmt.Errorf("in DeleteAsset: %w", err)
5961
}
62+
return nil
6063
}
6164

62-
func (atb *AssetTransferBasic) GetAllAssets() []byte {
65+
func (atb *AssetTransferBasic) GetAllAssets() ([]byte, error) {
6366
result, err := atb.contract.Evaluate("GetAllAssets")
6467
if err != nil {
65-
panic(err)
68+
return []byte{}, fmt.Errorf("in GetAllAssets: %w", err)
6669
}
67-
return result
70+
return result, nil
6871
}

off_chain_data/application-go/getAllAssets.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ func getAllAssets(clientConnection *grpc.ClientConn) {
2626

2727
contract := gateway.GetNetwork(channelName).GetContract(chaincodeName)
2828
smartContract := atb.NewAssetTransferBasic(contract)
29-
assets := smartContract.GetAllAssets()
29+
assets, err := smartContract.GetAllAssets()
30+
if err != nil {
31+
panic((err))
32+
}
3033

3134
fmt.Println(formatJSON(assets))
3235
}

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 {

0 commit comments

Comments
 (0)