github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/events/dx_callbacks.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package events 18 19 import ( 20 "encoding/json" 21 "fmt" 22 23 "github.com/kaleido-io/firefly/internal/i18n" 24 "github.com/kaleido-io/firefly/internal/log" 25 "github.com/kaleido-io/firefly/pkg/database" 26 "github.com/kaleido-io/firefly/pkg/dataexchange" 27 "github.com/kaleido-io/firefly/pkg/fftypes" 28 ) 29 30 func (em *eventManager) MessageReceived(dx dataexchange.Plugin, peerID string, data []byte) { 31 32 // Retry for persistence errors (not validation errors) 33 _ = em.retry.Do(em.ctx, "private batch received", func(attempt int) (bool, error) { 34 35 l := log.L(em.ctx) 36 l.Infof("Message received from '%s' (len=%d)", peerID, len(data)) 37 38 // Try to de-serialize it as a batch 39 var batch fftypes.Batch 40 err := json.Unmarshal(data, &batch) 41 if err != nil { 42 l.Errorf("Invalid batch: %s", err) 43 return false, nil 44 } 45 46 // Find the node associated with the peer 47 filter := database.NodeQueryFactory.NewFilter(em.ctx).Eq("dx.peer", peerID) 48 nodes, err := em.database.GetNodes(em.ctx, filter) 49 if err != nil { 50 l.Errorf("Failed to retrieve node: %v", err) 51 return true, err // retry for persistence error 52 } 53 if len(nodes) < 1 { 54 l.Errorf("Node not found for peer %s", peerID) 55 return false, nil 56 } 57 node := nodes[0] 58 59 // Find the identity in the mesage 60 batchOrg, err := em.database.GetOrganizationByIdentity(em.ctx, batch.Author) 61 if err != nil { 62 l.Errorf("Failed to retrieve batch org: %v", err) 63 return true, err // retry for persistence error 64 } 65 if batchOrg == nil { 66 l.Errorf("Org not found for identity %s", batch.Author) 67 return false, nil 68 } 69 70 // One of the orgs in the hierarchy of the batch author must be the owner of the peer node 71 candidate := batchOrg 72 foundNodeOrg := batch.Author == node.Owner 73 for !foundNodeOrg && candidate.Parent != "" { 74 parent := candidate.Parent 75 candidate, err = em.database.GetOrganizationByIdentity(em.ctx, parent) 76 if err != nil { 77 l.Errorf("Failed to retrieve node org '%s': %v", parent, err) 78 return true, err // retry for persistence error 79 } 80 if candidate == nil { 81 l.Errorf("Did not find org '%s' in chain for identity '%s'", parent, batchOrg.Identity) 82 return false, nil 83 } 84 foundNodeOrg = candidate.Identity == node.Owner 85 } 86 if !foundNodeOrg { 87 l.Errorf("No org in the chain matches owner '%s' of node '%s' ('%s')", node.Owner, node.ID, node.Name) 88 return false, nil 89 } 90 91 if err := em.persistBatch(em.ctx, &batch); err != nil { 92 l.Errorf("Batch received from %s/%s invalid: %s", node.Owner, node.Name, err) 93 return true, err // retry - persistBatch only returns retryable errors 94 } 95 96 em.aggregator.offchainBatches <- batch.ID 97 return false, nil 98 }) 99 100 } 101 102 func (em *eventManager) BLOBReceived(dx dataexchange.Plugin, peerID string, ns string, id fftypes.UUID) { 103 } 104 105 func (em *eventManager) TransferResult(dx dataexchange.Plugin, trackingID string, status fftypes.OpStatus, info string, additionalInfo fftypes.JSONObject) { 106 log.L(em.ctx).Infof("Transfer result %s=%s info='%s'", trackingID, status, info) 107 108 // Find a matching operation, for this plugin, with the specified ID. 109 // We retry a few times, as there's an outside possibility of the event arriving before we're finished persisting the operation itself 110 var operations []*fftypes.Operation 111 fb := database.OperationQueryFactory.NewFilter(em.ctx) 112 filter := fb.And( 113 fb.Eq("backendid", trackingID), 114 fb.Eq("plugin", dx.Name()), 115 ) 116 err := em.retry.Do(em.ctx, fmt.Sprintf("correlate transfer %s", trackingID), func(attempt int) (retry bool, err error) { 117 operations, err = em.database.GetOperations(em.ctx, filter) 118 if err == nil && len(operations) == 0 { 119 err = i18n.NewError(em.ctx, i18n.Msg404NotFound) 120 } 121 return (err != nil && attempt <= em.opCorrelationRetries), err 122 }) 123 if err != nil { 124 log.L(em.ctx).Warnf("Failed to correlate transfer ID '%s' with a submitted operation", trackingID) 125 return 126 } 127 128 update := database.OperationQueryFactory.NewUpdate(em.ctx). 129 Set("status", status). 130 Set("error", info). 131 Set("info", additionalInfo) 132 for _, op := range operations { 133 if err := em.database.UpdateOperation(em.ctx, op.ID, update); err != nil { 134 return 135 } 136 } 137 138 }