github.com/braveheart12/just@v0.8.7/ledger/artifactmanager/middleware.go (about)

     1  /*
     2   *    Copyright 2019 Insolar Technologies
     3   *
     4   *    Licensed under the Apache License, Version 2.0 (the "License");
     5   *    you may not use this file except in compliance with the License.
     6   *    You may obtain a copy of the License at
     7   *
     8   *        http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   *    Unless required by applicable law or agreed to in writing, software
    11   *    distributed under the License is distributed on an "AS IS" BASIS,
    12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *    See the License for the specific language governing permissions and
    14   *    limitations under the License.
    15   */
    16  
    17  package artifactmanager
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/pkg/errors"
    23  
    24  	"github.com/insolar/insolar/configuration"
    25  	"github.com/insolar/insolar/core"
    26  	"github.com/insolar/insolar/core/message"
    27  	"github.com/insolar/insolar/core/reply"
    28  	"github.com/insolar/insolar/instrumentation/inslogger"
    29  	"github.com/insolar/insolar/ledger/storage"
    30  	"github.com/insolar/insolar/ledger/storage/jet"
    31  )
    32  
    33  type middleware struct {
    34  	objectStorage  storage.ObjectStorage
    35  	jetStorage     storage.JetStorage
    36  	jetCoordinator core.JetCoordinator
    37  	messageBus     core.MessageBus
    38  	pulseStorage   core.PulseStorage
    39  	hotDataWaiter  HotDataWaiter
    40  	conf           *configuration.Ledger
    41  	handler        *MessageHandler
    42  }
    43  
    44  func newMiddleware(
    45  	h *MessageHandler,
    46  ) *middleware {
    47  	return &middleware{
    48  		objectStorage:  h.ObjectStorage,
    49  		jetStorage:     h.JetStorage,
    50  		jetCoordinator: h.JetCoordinator,
    51  		messageBus:     h.Bus,
    52  		pulseStorage:   h.PulseStorage,
    53  		hotDataWaiter:  h.HotDataWaiter,
    54  		handler:        h,
    55  		conf:           h.conf,
    56  	}
    57  }
    58  
    59  func (m *middleware) addFieldsToLogger(handler core.MessageHandler) core.MessageHandler {
    60  	return func(ctx context.Context, parcel core.Parcel) (core.Reply, error) {
    61  		ctx, _ = inslogger.WithField(ctx, "targetid", parcel.DefaultTarget().String())
    62  
    63  		return handler(ctx, parcel)
    64  	}
    65  }
    66  
    67  type jetKey struct{}
    68  
    69  func contextWithJet(ctx context.Context, jetID core.RecordID) context.Context {
    70  	return context.WithValue(ctx, jetKey{}, jetID)
    71  }
    72  
    73  func jetFromContext(ctx context.Context) core.RecordID {
    74  	val := ctx.Value(jetKey{})
    75  	j, ok := val.(core.RecordID)
    76  	if !ok {
    77  		panic("failed to extract jet from context")
    78  	}
    79  
    80  	return j
    81  }
    82  
    83  func (m *middleware) zeroJetForHeavy(handler core.MessageHandler) core.MessageHandler {
    84  	return func(ctx context.Context, parcel core.Parcel) (core.Reply, error) {
    85  		return handler(contextWithJet(ctx, *jet.NewID(0, nil)), parcel)
    86  	}
    87  }
    88  
    89  func addJetIDToLogger(ctx context.Context, jetID core.RecordID) context.Context {
    90  	ctx, _ = inslogger.WithField(ctx, "jetid", jetID.DebugString())
    91  
    92  	return ctx
    93  }
    94  
    95  func (m *middleware) checkJet(handler core.MessageHandler) core.MessageHandler {
    96  	return func(ctx context.Context, parcel core.Parcel) (core.Reply, error) {
    97  		msg := parcel.Message()
    98  		if msg.DefaultTarget() == nil {
    99  			return nil, errors.New("unexpected message")
   100  		}
   101  
   102  		// FIXME: @andreyromancev. 17.01.19. Temporary allow any genesis request. Remove it.
   103  		if parcel.Pulse() == core.FirstPulseNumber {
   104  			return handler(contextWithJet(ctx, *jet.NewID(0, nil)), parcel)
   105  		}
   106  
   107  		// Check token jet.
   108  		token := parcel.DelegationToken()
   109  		if token != nil {
   110  			// Calculate jet for target pulse.
   111  			target := *msg.DefaultTarget().Record()
   112  			pulse := target.Pulse()
   113  			switch tm := msg.(type) {
   114  			case *message.GetObject:
   115  				pulse = tm.State.Pulse()
   116  			case *message.GetChildren:
   117  				if tm.FromChild == nil {
   118  					return nil, errors.New("fetching children without child pointer is forbidden")
   119  				}
   120  				pulse = tm.FromChild.Pulse()
   121  			case *message.GetRequest:
   122  				pulse = tm.Request.Pulse()
   123  			}
   124  			jetID, actual := m.jetStorage.FindJet(ctx, pulse, target)
   125  			if !actual {
   126  				inslogger.FromContext(ctx).WithFields(map[string]interface{}{
   127  					"msg":   msg.Type().String(),
   128  					"jet":   jetID.DebugString(),
   129  					"pulse": pulse,
   130  				}).Error("jet is not actual")
   131  			}
   132  
   133  			return handler(contextWithJet(ctx, *jetID), parcel)
   134  		}
   135  
   136  		// Calculate jet and pulse.
   137  		var jetID *core.RecordID
   138  		var pulse core.PulseNumber
   139  		if msg.DefaultTarget().Record().Pulse() == core.PulseNumberJet {
   140  			jetID = msg.DefaultTarget().Record()
   141  		} else {
   142  			if gr, ok := msg.(*message.GetRequest); ok {
   143  				pulse = gr.Request.Pulse()
   144  			} else {
   145  				pulse = parcel.Pulse()
   146  			}
   147  
   148  			var err error
   149  			jetID, err = m.handler.jetTreeUpdater.fetchJet(ctx, *msg.DefaultTarget().Record(), pulse)
   150  			if err != nil {
   151  				return nil, errors.Wrap(err, "failed to fetch jet tree")
   152  			}
   153  		}
   154  
   155  		// Check if jet is ours.
   156  		node, err := m.jetCoordinator.LightExecutorForJet(ctx, *jetID, pulse)
   157  		if err != nil {
   158  			return nil, errors.Wrap(err, "failed to calculate executor for jet")
   159  		}
   160  		if *node != m.jetCoordinator.Me() {
   161  			return &reply.JetMiss{JetID: *jetID, Pulse: pulse}, nil
   162  		}
   163  
   164  		ctx = addJetIDToLogger(ctx, *jetID)
   165  
   166  		return handler(contextWithJet(ctx, *jetID), parcel)
   167  	}
   168  }
   169  
   170  func (m *middleware) waitForHotData(handler core.MessageHandler) core.MessageHandler {
   171  	return func(ctx context.Context, parcel core.Parcel) (core.Reply, error) {
   172  		// TODO: 15.01.2019 @egorikas
   173  		// Hack is needed for genesis
   174  		if parcel.Pulse() == core.FirstPulseNumber {
   175  			return handler(ctx, parcel)
   176  		}
   177  
   178  		// If the call is a call in redirect-chain
   179  		// skip waiting for the hot records
   180  		if parcel.DelegationToken() != nil {
   181  			return handler(ctx, parcel)
   182  		}
   183  
   184  		jetID := jetFromContext(ctx)
   185  		err := m.hotDataWaiter.Wait(ctx, jetID)
   186  		if err != nil {
   187  			return &reply.Error{ErrType: reply.ErrHotDataTimeout}, nil
   188  		}
   189  		return handler(ctx, parcel)
   190  	}
   191  }
   192  
   193  func (m *middleware) releaseHotDataWaiters(handler core.MessageHandler) core.MessageHandler {
   194  	return func(ctx context.Context, parcel core.Parcel) (core.Reply, error) {
   195  		rep, err := handler(ctx, parcel)
   196  
   197  		hotDataMessage := parcel.Message().(*message.HotData)
   198  		jetID := hotDataMessage.Jet.Record()
   199  		unlockErr := m.hotDataWaiter.Unlock(ctx, *jetID)
   200  		if unlockErr != nil {
   201  			inslogger.FromContext(ctx).Error(err)
   202  		}
   203  
   204  		return rep, err
   205  	}
   206  }