github.com/igggame/nebulas-go@v2.1.0+incompatible/core/compatibility.go (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package core
    20  
    21  import (
    22  	"bytes"
    23  	"errors"
    24  	"os"
    25  	"path/filepath"
    26  	"strconv"
    27  	"strings"
    28  
    29  	"github.com/nebulasio/go-nebulas/util/logging"
    30  	"github.com/sirupsen/logrus"
    31  )
    32  
    33  const (
    34  	// MainNetID mainnet id
    35  	MainNetID uint32 = 1
    36  
    37  	// TestNetID testnet id
    38  	TestNetID uint32 = 1001
    39  )
    40  
    41  /**********     js lib relative  BEGIN   **********/
    42  const (
    43  	// DefaultV8JSLibVersion default version
    44  	DefaultV8JSLibVersion = "1.0.0"
    45  )
    46  
    47  type version struct {
    48  	major, minor, patch int
    49  }
    50  
    51  // var ..
    52  var (
    53  	// NOTE: versions should be arranged in ascending order
    54  	// 		map[libname][versions]
    55  	V8JSLibs = map[string][]string{
    56  		"execution_env.js":       {"1.0.0", "1.0.5"},
    57  		"bignumber.js":           {"1.0.0"},
    58  		"random.js":              {"1.0.0", "1.0.5", "1.1.0"},
    59  		"date.js":                {"1.0.0", "1.0.5"},
    60  		"tsc.js":                 {"1.0.0"},
    61  		"util.js":                {"1.0.0"},
    62  		"esprima.js":             {"1.0.0"},
    63  		"assert.js":              {"1.0.0"},
    64  		"instruction_counter.js": {"1.0.0", "1.1.0"},
    65  		"typescriptServices.js":  {"1.0.0"},
    66  		"blockchain.js":          {"1.0.0", "1.0.5", "1.1.0"},
    67  		"console.js":             {"1.0.0"},
    68  		"event.js":               {"1.0.0"},
    69  		"storage.js":             {"1.0.0"},
    70  		"crypto.js":              {"1.0.5"},
    71  		"uint.js":                {"1.0.5"},
    72  	}
    73  
    74  	digitalized = make(map[string][]*version)
    75  )
    76  
    77  var (
    78  	// ErrInvalidJSLibVersion ..
    79  	ErrInvalidJSLibVersion = errors.New("invalid js lib version")
    80  )
    81  
    82  /**********     js lib relative  END   **********/
    83  
    84  // V8JSLibVersionHeightMap key is version in string format, value is height
    85  type V8JSLibVersionHeightMap struct {
    86  	Data     map[string]uint64
    87  	DescKeys []string
    88  }
    89  
    90  // GetHeightOfVersion ..
    91  func (v *V8JSLibVersionHeightMap) GetHeightOfVersion(version string) uint64 {
    92  	if r, ok := v.Data[version]; ok {
    93  		return r
    94  	}
    95  	return 0
    96  }
    97  
    98  func (v *V8JSLibVersionHeightMap) String() string {
    99  	var buf bytes.Buffer
   100  	buf.WriteString("{")
   101  	for _, ver := range v.DescKeys {
   102  		if buf.Len() > 1 {
   103  			buf.WriteString(",")
   104  		}
   105  		buf.WriteString(ver + "=" + strconv.FormatUint(v.Data[ver], 10))
   106  	}
   107  	buf.WriteString("}")
   108  	return buf.String()
   109  }
   110  
   111  func (v *V8JSLibVersionHeightMap) validate() {
   112  	var lastVersion *version
   113  	for _, key := range v.DescKeys {
   114  		cur, err := parseVersion(key)
   115  		if err != nil {
   116  			logging.VLog().WithFields(logrus.Fields{
   117  				"version": key,
   118  				"err":     err,
   119  			}).Fatal("parse version error.")
   120  		}
   121  
   122  		if lastVersion != nil {
   123  			if compareVersion(cur, lastVersion) >= 0 || v.Data[key] >= v.Data[lastVersion.String()] {
   124  				logging.VLog().WithFields(logrus.Fields{
   125  					"version": key,
   126  					"height":  v.Data[key],
   127  				}).Fatal("non descending order version map.")
   128  			}
   129  		}
   130  
   131  		lastVersion = cur
   132  	}
   133  }
   134  
   135  // Compatibility ..
   136  type Compatibility interface {
   137  	TransferFromContractEventRecordableHeight() uint64
   138  	AcceptFuncAvailableHeight() uint64
   139  	RandomAvailableHeight() uint64
   140  	DateAvailableHeight() uint64
   141  	RecordCallContractResultHeight() uint64
   142  	NvmMemoryLimitWithoutInjectHeight() uint64
   143  	WsResetRecordDependencyHeight() uint64 //reserve address of to
   144  	V8JSLibVersionControlHeight() uint64
   145  	TransferFromContractFailureEventRecordableHeight() uint64
   146  	NewNvmExeTimeoutConsumeGasHeight() uint64
   147  	NvmExeTimeoutHeight() []uint64
   148  	V8JSLibVersionHeightMap() *V8JSLibVersionHeightMap
   149  	NvmGasLimitWithoutTimeoutHeight() uint64
   150  	WsResetRecordDependencyHeight2() uint64 //reserve change log
   151  	TransferFromContractFailureEventRecordableHeight2() uint64
   152  	NvmValueCheckUpdateHeight() uint64
   153  	NbreAvailableHeight() uint64
   154  	Nrc20SecurityCheckHeight() uint64
   155  	NbreSplitHeight() uint64
   156  }
   157  
   158  // NebCompatibility ..
   159  var NebCompatibility = NewCompatibilityTestNet()
   160  
   161  // SetCompatibilityOptions set compatibility height according to chain_id
   162  func SetCompatibilityOptions(chainID uint32) {
   163  
   164  	if chainID == MainNetID {
   165  		NebCompatibility = NewCompatibilityMainNet()
   166  	} else if chainID == TestNetID {
   167  		NebCompatibility = NewCompatibilityTestNet()
   168  	} else {
   169  		NebCompatibility = NewCompatibilityLocal()
   170  	}
   171  
   172  	logging.VLog().WithFields(logrus.Fields{
   173  		"chain_id": chainID,
   174  		"TransferFromContractEventRecordableHeight": NebCompatibility.TransferFromContractEventRecordableHeight(),
   175  		"AcceptFuncAvailableHeight":                 NebCompatibility.AcceptFuncAvailableHeight(),
   176  		"RandomAvailableHeight":                     NebCompatibility.RandomAvailableHeight(),
   177  		"DateAvailableHeight":                       NebCompatibility.DateAvailableHeight(),
   178  		"RecordCallContractResultHeight":            NebCompatibility.RecordCallContractResultHeight(),
   179  		"NvmMemoryLimitWithoutInjectHeight":         NebCompatibility.NvmMemoryLimitWithoutInjectHeight(),
   180  		"WsResetRecordDependencyHeight":             NebCompatibility.WsResetRecordDependencyHeight(),
   181  		"WsResetRecordDependencyHeight2":            NebCompatibility.WsResetRecordDependencyHeight2(),
   182  		"V8JSLibVersionControlHeight":               NebCompatibility.V8JSLibVersionControlHeight(),
   183  		"V8JSLibVersionHeightMap":                   NebCompatibility.V8JSLibVersionHeightMap().String(),
   184  		"TransferFromContractFailureHeight":         NebCompatibility.TransferFromContractFailureEventRecordableHeight(),
   185  		"TransferFromContractFailureHeight2":        NebCompatibility.TransferFromContractFailureEventRecordableHeight2(),
   186  		"NewNvmExeTimeoutConsumeGasHeight":          NebCompatibility.NewNvmExeTimeoutConsumeGasHeight(),
   187  		"NvmExeTimeoutHeight":                       NebCompatibility.NvmExeTimeoutHeight(),
   188  		"NbreAvailableHeight":                       NebCompatibility.NbreAvailableHeight(),
   189  	}).Info("Set compatibility options.")
   190  
   191  	NebCompatibility.V8JSLibVersionHeightMap().validate()
   192  	checkJSLib()
   193  }
   194  
   195  // FindLastNearestLibVersion ..
   196  func FindLastNearestLibVersion(deployVersion, libname string) string {
   197  	if len(deployVersion) == 0 || len(libname) == 0 {
   198  		logging.VLog().WithFields(logrus.Fields{
   199  			"libname":       libname,
   200  			"deployVersion": deployVersion,
   201  		}).Error("empty arguments.")
   202  		return ""
   203  	}
   204  
   205  	if libs, ok := digitalized[libname]; ok {
   206  		v, err := parseVersion(deployVersion)
   207  		if err != nil {
   208  			logging.VLog().WithFields(logrus.Fields{
   209  				"err":           err,
   210  				"deployVersion": deployVersion,
   211  				"lib":           libname,
   212  			}).Debug("parse deploy version error.")
   213  			return ""
   214  		}
   215  		for i := len(libs) - 1; i >= 0; i-- {
   216  			if compareVersion(libs[i], v) <= 0 {
   217  				/*
   218  					logging.VLog().WithFields(logrus.Fields{
   219  						"libname":       libname,
   220  						"deployVersion": deployVersion,
   221  						"return":        libs[i],
   222  					}).Debug("filter js lib.")
   223  				*/
   224  				return V8JSLibs[libname][i]
   225  			}
   226  		}
   227  	} else {
   228  		logging.VLog().WithFields(logrus.Fields{
   229  			"libname":       libname,
   230  			"deployVersion": deployVersion,
   231  		}).Debug("js lib not configured.")
   232  	}
   233  	return ""
   234  }
   235  
   236  func compareVersion(a, b *version) int {
   237  	if a.major > b.major {
   238  		return 1
   239  	}
   240  	if a.major < b.major {
   241  		return -1
   242  	}
   243  
   244  	if a.minor > b.minor {
   245  		return 1
   246  	}
   247  	if a.minor < b.minor {
   248  		return -1
   249  	}
   250  
   251  	if a.patch > b.patch {
   252  		return 1
   253  	}
   254  	if a.patch < b.patch {
   255  		return -1
   256  	}
   257  	return 0
   258  }
   259  
   260  func checkJSLib() {
   261  	for lib, vers := range V8JSLibs {
   262  		for _, ver := range vers {
   263  			p := filepath.Join("lib", ver, lib)
   264  			fi, err := os.Stat(p)
   265  			if os.IsNotExist(err) {
   266  				logging.VLog().WithFields(logrus.Fields{
   267  					"path": p,
   268  				}).Fatal("lib file not exist.")
   269  			}
   270  			if fi.IsDir() {
   271  				logging.VLog().WithFields(logrus.Fields{
   272  					"path": p,
   273  				}).Fatal("directory already exists with the same name.")
   274  			}
   275  
   276  			logging.VLog().WithFields(logrus.Fields{
   277  				"path": p,
   278  			}).Debug("check js lib.")
   279  		}
   280  	}
   281  }
   282  
   283  func parseVersion(ver string) (*version, error) {
   284  	ss := strings.Split(ver, ".")
   285  	if len(ss) != 3 {
   286  		return nil, ErrInvalidJSLibVersion
   287  	}
   288  
   289  	major, err := strconv.Atoi(ss[0])
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  
   294  	minor, err := strconv.Atoi(ss[1])
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	patch, err := strconv.Atoi(ss[2])
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  	return &version{major, minor, patch}, nil
   304  }
   305  
   306  func (v *version) String() string {
   307  	return strings.Join([]string{
   308  		strconv.Itoa(v.major),
   309  		strconv.Itoa(v.minor),
   310  		strconv.Itoa(v.patch),
   311  	}, ".")
   312  }
   313  
   314  // convert V8JSLibs from string to type `version`
   315  func init() {
   316  	for lib, vers := range V8JSLibs {
   317  		for _, ver := range vers {
   318  			v, err := parseVersion(ver)
   319  			if err != nil {
   320  				logging.VLog().WithFields(logrus.Fields{
   321  					"err":     err,
   322  					"lib":     lib,
   323  					"version": ver,
   324  				}).Fatal("parse js lib version error.")
   325  			}
   326  
   327  			if _, ok := digitalized[lib]; !ok {
   328  				digitalized[lib] = make([]*version, 0)
   329  			}
   330  			digitalized[lib] = append(digitalized[lib], v)
   331  		}
   332  	}
   333  }
   334  
   335  // GetMaxV8JSLibVersionAtHeight ..
   336  func GetMaxV8JSLibVersionAtHeight(blockHeight uint64) string {
   337  	m := NebCompatibility.V8JSLibVersionHeightMap()
   338  	for _, v := range m.DescKeys {
   339  		if blockHeight >= m.Data[v] {
   340  			return v
   341  		}
   342  	}
   343  	return ""
   344  }
   345  
   346  // V8BlockSeedAvailableAtHeight ..
   347  func V8BlockSeedAvailableAtHeight(blockHeight uint64) bool {
   348  	/*  For old contract, Blockchain.block.seed should not be disable
   349  	 * 		return blockHeight >= NebCompatibility.RandomAvailableHeight() &&
   350  	 * 		blockHeight < NebCompatibility.V8JSLibVersionHeightMap().GetHeightOfVersion("1.1.0")
   351  	 */
   352  
   353  	return blockHeight >= NebCompatibility.RandomAvailableHeight()
   354  }
   355  
   356  // V8JSLibVersionControlAtHeight ..
   357  func V8JSLibVersionControlAtHeight(blockHeight uint64) bool {
   358  	return blockHeight >= NebCompatibility.V8JSLibVersionControlHeight()
   359  }
   360  
   361  // RandomAvailableAtHeight ..
   362  func RandomAvailableAtHeight(blockHeight uint64) bool {
   363  	return blockHeight >= NebCompatibility.RandomAvailableHeight()
   364  }
   365  
   366  // DateAvailableAtHeight ..
   367  func DateAvailableAtHeight(blockHeight uint64) bool {
   368  	return blockHeight >= NebCompatibility.DateAvailableHeight()
   369  }
   370  
   371  // AcceptAvailableAtHeight ..
   372  func AcceptAvailableAtHeight(blockHeight uint64) bool {
   373  	return blockHeight >= NebCompatibility.AcceptFuncAvailableHeight()
   374  }
   375  
   376  // WsResetRecordDependencyAtHeight ..
   377  func WsResetRecordDependencyAtHeight(blockHeight uint64) bool {
   378  	return blockHeight >= NebCompatibility.WsResetRecordDependencyHeight()
   379  }
   380  
   381  // WsResetRecordDependencyAtHeight2 ..
   382  func WsResetRecordDependencyAtHeight2(blockHeight uint64) bool {
   383  	return blockHeight >= NebCompatibility.WsResetRecordDependencyHeight2()
   384  }
   385  
   386  // RecordCallContractResultAtHeight ..
   387  func RecordCallContractResultAtHeight(blockHeight uint64) bool {
   388  	return blockHeight >= NebCompatibility.RecordCallContractResultHeight()
   389  }
   390  
   391  // NvmMemoryLimitWithoutInjectAtHeight ..
   392  func NvmMemoryLimitWithoutInjectAtHeight(blockHeight uint64) bool {
   393  	return blockHeight >= NebCompatibility.NvmMemoryLimitWithoutInjectHeight()
   394  }
   395  
   396  // NewNvmExeTimeoutConsumeGasAtHeight ..
   397  func NewNvmExeTimeoutConsumeGasAtHeight(blockHeight uint64) bool {
   398  	return blockHeight >= NebCompatibility.NewNvmExeTimeoutConsumeGasHeight()
   399  }
   400  
   401  // TransferFromContractEventRecordableAtHeight ..
   402  func TransferFromContractEventRecordableAtHeight(blockHeight uint64) bool {
   403  	return blockHeight >= NebCompatibility.TransferFromContractEventRecordableHeight()
   404  }
   405  
   406  // TransferFromContractFailureEventRecordableAtHeight ..
   407  func TransferFromContractFailureEventRecordableAtHeight(blockHeight uint64) bool {
   408  	return blockHeight >= NebCompatibility.TransferFromContractFailureEventRecordableHeight()
   409  }
   410  
   411  // TransferFromContractFailureEventRecordableAtHeight2 ..
   412  func TransferFromContractFailureEventRecordableAtHeight2(blockHeight uint64) bool {
   413  	return blockHeight >= NebCompatibility.TransferFromContractFailureEventRecordableHeight2()
   414  }
   415  
   416  // NvmGasLimitWithoutTimeoutAtHeight ..
   417  func NvmGasLimitWithoutTimeoutAtHeight(blockHeight uint64) bool {
   418  	return blockHeight >= NebCompatibility.NvmGasLimitWithoutTimeoutHeight()
   419  }
   420  
   421  // NvmExeTimeoutAtHeight ..
   422  func NvmExeTimeoutAtHeight(blockHeight uint64) bool {
   423  	for _, height := range NebCompatibility.NvmExeTimeoutHeight() {
   424  		if blockHeight == height {
   425  			return true
   426  		}
   427  	}
   428  	return false
   429  }
   430  
   431  // GetNearestInstructionCounterVersionAtHeight ..
   432  func GetNearestInstructionCounterVersionAtHeight(blockHeight uint64) string {
   433  	m := NebCompatibility.V8JSLibVersionHeightMap()
   434  	for _, v := range m.DescKeys {
   435  		if v == "1.1.0" && blockHeight >= m.Data[v] {
   436  			return v
   437  		}
   438  	}
   439  	return "1.0.0"
   440  }
   441  
   442  // EnableInnerContractAtHeight ..
   443  func EnableInnerContractAtHeight(blockHeight uint64) bool {
   444  	m := NebCompatibility.V8JSLibVersionHeightMap()
   445  	return blockHeight >= m.Data["1.1.0"]
   446  }
   447  
   448  // NvmValueCheckUpdateHeight ..
   449  func NvmValueCheckUpdateHeight(blockHeight uint64) bool {
   450  	return blockHeight >= NebCompatibility.NvmValueCheckUpdateHeight()
   451  }
   452  
   453  // NbreAvailableHeight ..
   454  func NbreAvailableHeight(blockHeight uint64) bool {
   455  	return blockHeight >= NebCompatibility.NbreAvailableHeight()
   456  }
   457  
   458  // Nrc20SecurityCheckAtHeight ..
   459  func Nrc20SecurityCheckAtHeight(blockHeight uint64) bool {
   460  	return blockHeight >= NebCompatibility.Nrc20SecurityCheckHeight()
   461  }
   462  
   463  // NbreSplitAtHeight ..
   464  func NbreSplitAtHeight(blockHeight uint64) bool {
   465  	return blockHeight >= NebCompatibility.NbreSplitHeight()
   466  }