github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/validate/blockvalidate.go (about)

     1  // Copyright 2021 The TrueBlocks Authors. All rights reserved.
     2  // Use of this source code is governed by a license that can
     3  // be found in the LICENSE file.
     4  
     5  package validate
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    14  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers"
    15  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/tslib"
    16  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
    17  
    18  	"github.com/bykof/gostradamus"
    19  )
    20  
    21  func IsBlockHash(str string) bool {
    22  	if !strings.HasPrefix(str, "0x") {
    23  		return false
    24  	}
    25  
    26  	if len(str) != 66 {
    27  		return false
    28  	}
    29  
    30  	if !base.IsHex(str) {
    31  		return false
    32  	}
    33  
    34  	return true
    35  }
    36  
    37  type blknum_t = uint32
    38  
    39  func IsTimestamp(str string) (bool, blknum_t) {
    40  	ok, bn := IsBlockNumber(str)
    41  	if !ok {
    42  		return false, 0
    43  	}
    44  	return bn >= utils.EarliestEvmTs, bn
    45  }
    46  
    47  func IsBlockNumber(str string) (bool, blknum_t) {
    48  	base := 10
    49  	source := str
    50  
    51  	if strings.HasPrefix(str, "0x") {
    52  		base = 16
    53  		source = str[2:]
    54  	}
    55  
    56  	value, err := strconv.ParseUint(source, base, 32)
    57  	if err != nil {
    58  		return false, 0
    59  	}
    60  
    61  	return true, blknum_t(value)
    62  }
    63  
    64  func IsBlockNumberList(strs []string) (bool, []blknum_t) {
    65  	result := make([]blknum_t, len(strs))
    66  
    67  	for index, stringValue := range strs {
    68  		check, value := IsBlockNumber(stringValue)
    69  		if !check {
    70  			return false, nil
    71  		}
    72  
    73  		result[index] = value
    74  	}
    75  
    76  	return true, result
    77  }
    78  
    79  func IsDateTimeString(str string) bool {
    80  	if strings.Count(str, "-") != 2 {
    81  		return false
    82  	}
    83  
    84  	bRange, err := identifiers.NewBlockRange(str)
    85  	if err != nil {
    86  		return false
    87  	}
    88  	return bRange.StartType == identifiers.BlockDate
    89  }
    90  
    91  func ToIsoDateStr2(dateStr string) string {
    92  	// assumes an already validated date string
    93  	str := strings.Replace(dateStr, "T", " ", -1)
    94  	if strings.Count(str, ":") == 0 {
    95  		if strings.Count(str, " ") == 1 {
    96  			str += ":00:00"
    97  		} else {
    98  			str += " 00:00:00"
    99  		}
   100  	} else if strings.Count(str, ":") == 1 {
   101  		str += ":00"
   102  	}
   103  	str = strings.Replace(str, " ", "T", -1)
   104  	str += ".000000"
   105  	return str
   106  }
   107  
   108  func isBeforeFirstBlock(chain, dateStr string) bool {
   109  	if !IsDateTimeString(dateStr) {
   110  		return false
   111  	}
   112  
   113  	isoStr := ToIsoDateStr2(dateStr)
   114  	dt, _ := gostradamus.Parse(isoStr, gostradamus.Iso8601) // already validated as a date
   115  	firstDate, _ := tslib.FromNameToDate(chain, "0")
   116  	return dt.Time().Before(firstDate.Time())
   117  }
   118  
   119  func IsRange(chain, str string) (bool, error) {
   120  	// Disallow "start only ranges" like "1000" or "london"
   121  	if !strings.Contains(str, "-") {
   122  		return false, &InvalidIdentifierLiteralError{
   123  			Value: str,
   124  		}
   125  	}
   126  
   127  	bRange, err := identifiers.NewBlockRange(str)
   128  
   129  	if err == nil {
   130  		if bRange.Start.Special == "latest" {
   131  			return false, errors.New("cannot start range with 'latest'")
   132  		}
   133  
   134  		if bRange.StartType == identifiers.BlockSpecial &&
   135  			!tslib.IsSpecialBlock(chain, bRange.Start.Special) {
   136  			return false, &InvalidIdentifierLiteralError{
   137  				Value: bRange.Start.Special,
   138  			}
   139  		}
   140  
   141  		if bRange.EndType == identifiers.BlockSpecial &&
   142  			!tslib.IsSpecialBlock(chain, bRange.End.Special) {
   143  			return false, &InvalidIdentifierLiteralError{
   144  				Value: bRange.End.Special,
   145  			}
   146  		}
   147  
   148  		onlyNumbers := bRange.StartType == identifiers.BlockNumber &&
   149  			bRange.EndType == identifiers.BlockNumber
   150  
   151  		if onlyNumbers && bRange.Start.Number >= bRange.End.Number {
   152  			return false, errors.New("'stop' must be strictly larger than 'start'")
   153  		}
   154  
   155  		return true, nil
   156  	}
   157  
   158  	if modifierErr, ok := err.(*identifiers.WrongModifierError); ok {
   159  		return false, errors.New("Input argument appears to be invalid. No such skip marker: " + modifierErr.Token)
   160  	}
   161  
   162  	return false, err
   163  }
   164  
   165  // Errors returned by ValidateIdentifiers (note: it can also return an
   166  // error passed from IsRange)
   167  
   168  var ErrTooManyRanges = errors.New("too many ranges")
   169  
   170  type InvalidIdentifierLiteralError struct {
   171  	Value string
   172  	Msg   string
   173  }
   174  
   175  func (e *InvalidIdentifierLiteralError) Error() string {
   176  	if len(e.Msg) == 0 {
   177  		e.Msg = "is not a valid identifier."
   178  	}
   179  	return fmt.Sprintf("The given value '%s' %s", e.Value, e.Msg)
   180  }
   181  
   182  func IsValidBlockId(chain string, ids []string, validTypes ValidArgumentType) (bool, error) {
   183  	err := ValidateIdentifiers(chain, ids, validTypes, 1, nil)
   184  	return err == nil, err
   185  }