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 }