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  }