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  }