code.vegaprotocol.io/vega@v0.79.0/libs/context/context.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package context 17 18 import ( 19 "context" 20 "errors" 21 "strings" 22 23 uuid "github.com/satori/go.uuid" 24 ) 25 26 type ( 27 remoteIPAddrKey int 28 traceIDT int 29 blockHeight int 30 chainID int 31 txHash int 32 snapshot int 33 ) 34 35 var ( 36 clientRemoteIPAddrKey remoteIPAddrKey 37 traceIDKey traceIDT 38 blockHeightKey blockHeight 39 chainIDKey chainID 40 txHashKey txHash 41 snapshotKey snapshot 42 43 ErrBlockHeightMissing = errors.New("no or invalid block height set on context") 44 ErrChainIDMissing = errors.New("no or invalid chain id set on context") 45 ErrTxHashMissing = errors.New("no or invalid transaction hash set on context") 46 ) 47 48 // WithRemoteIPAddr wrap the context into a new context 49 // and embed the ip addr as a key. 50 func WithRemoteIPAddr(ctx context.Context, addr string) context.Context { 51 return context.WithValue(ctx, clientRemoteIPAddrKey, addr) 52 } 53 54 // RemoteIPAddrFromContext returns the remote IP addr value stored in ctx, if any. 55 func RemoteIPAddrFromContext(ctx context.Context) (string, bool) { 56 u, ok := ctx.Value(clientRemoteIPAddrKey).(string) 57 return u, ok 58 } 59 60 // TraceIDFromContext get traceID from context (add one if none is set). 61 func TraceIDFromContext(ctx context.Context) (context.Context, string) { 62 tID := ctx.Value(traceIDKey) 63 if tID == nil { 64 if h, _ := BlockHeightFromContext(ctx); h == 0 { 65 ctx = context.WithValue(ctx, traceIDKey, "genesis") 66 return ctx, "genesis" 67 } 68 stID := uuid.NewV4().String() 69 ctx = context.WithValue(ctx, traceIDKey, stID) 70 return ctx, stID 71 } 72 stID, ok := tID.(string) 73 if !ok { 74 stID = uuid.NewV4().String() 75 ctx = context.WithValue(ctx, traceIDKey, stID) 76 } 77 return ctx, stID 78 } 79 80 func BlockHeightFromContext(ctx context.Context) (uint64, error) { 81 hv := ctx.Value(blockHeightKey) 82 if hv == nil { 83 return 0, ErrBlockHeightMissing 84 } 85 h, ok := hv.(uint64) 86 if !ok { 87 return 0, ErrBlockHeightMissing 88 } 89 return h, nil 90 } 91 92 func ChainIDFromContext(ctx context.Context) (string, error) { 93 cv := ctx.Value(chainIDKey) 94 if cv == nil { 95 return "", ErrChainIDMissing 96 } 97 c, ok := cv.(string) 98 if !ok { 99 return "", ErrChainIDMissing 100 } 101 return c, nil 102 } 103 104 func TxHashFromContext(ctx context.Context) (string, error) { 105 cv := ctx.Value(txHashKey) 106 if cv == nil { 107 // if this is not happening in the context of a transaction, use the hash of the block 108 cv = ctx.Value(traceIDKey) 109 if cv == nil { 110 return "", ErrTxHashMissing 111 } 112 } 113 c, ok := cv.(string) 114 if !ok { 115 return "", ErrTxHashMissing 116 } 117 return c, nil 118 } 119 120 // WithTraceID returns a context with a traceID value. 121 func WithTraceID(ctx context.Context, tID string) context.Context { 122 tID = strings.ToUpper(tID) 123 return context.WithValue(ctx, traceIDKey, tID) 124 } 125 126 func WithBlockHeight(ctx context.Context, h uint64) context.Context { 127 return context.WithValue(ctx, blockHeightKey, h) 128 } 129 130 func WithChainID(ctx context.Context, chainID string) context.Context { 131 return context.WithValue(ctx, chainIDKey, chainID) 132 } 133 134 func WithTxHash(ctx context.Context, txHash string) context.Context { 135 txHash = strings.ToUpper(txHash) 136 return context.WithValue(ctx, txHashKey, txHash) 137 } 138 139 type snapshotInfo struct { 140 version string 141 upgrade bool 142 } 143 144 func WithSnapshotInfo(ctx context.Context, version string, upgrade bool) context.Context { 145 return context.WithValue(ctx, snapshotKey, snapshotInfo{version: version, upgrade: upgrade}) 146 } 147 148 // InProgressSnapshotRestore returns whether the data in the contexts tells us that a 149 // snapshot restore is in progress. 150 func InProgressSnapshotRestore(ctx context.Context) bool { 151 v := ctx.Value(snapshotKey) 152 if v == nil { 153 return false 154 } 155 _, ok := v.(snapshotInfo) 156 return ok 157 } 158 159 // InProgressUpgradeFrom returns whether the data in the contexts tells us that the 160 // node is restoring from a snapshot taken for a protocol-upgrade by the given version. 161 func InProgressUpgradeFrom(ctx context.Context, from string) bool { 162 v := ctx.Value(snapshotKey) 163 if v == nil { 164 return false 165 } 166 si, ok := v.(snapshotInfo) 167 if !ok { 168 return false 169 } 170 return from == si.version && si.upgrade 171 } 172 173 // InProgressUpgradeFromMultiple returns whether the data in the contexts tells us that the 174 // node is restoring from a snapshot taken for a protocol-upgrade by one of the given versions. 175 // This can be useful in situations where mainnet and fairground are running different versions. 176 func InProgressUpgradeFromMultiple(ctx context.Context, versions ...string) bool { 177 v := ctx.Value(snapshotKey) 178 if v == nil { 179 return false 180 } 181 si, ok := v.(snapshotInfo) 182 if !ok || !si.upgrade { 183 return false 184 } 185 for _, from := range versions { 186 if from == si.version { 187 return true 188 } 189 } 190 return false 191 } 192 193 // InProgressUpgrade returns whether the data in the contexts tells us that the 194 // node is restoring from a snapshot taken for a protocol-upgrade. 195 func InProgressUpgrade(ctx context.Context) bool { 196 v := ctx.Value(snapshotKey) 197 if v == nil { 198 return false 199 } 200 si, ok := v.(snapshotInfo) 201 if !ok { 202 return false 203 } 204 return si.upgrade 205 }