github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/storage.go (about)

     1  // Copyright (C) 2017 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 nvm
    20  
    21  import "C"
    22  
    23  import (
    24  	"errors"
    25  	"regexp"
    26  	"unsafe"
    27  
    28  	"github.com/nebulasio/go-nebulas/core"
    29  
    30  	"github.com/nebulasio/go-nebulas/common/trie"
    31  	"github.com/nebulasio/go-nebulas/util/logging"
    32  	"github.com/sirupsen/logrus"
    33  )
    34  
    35  var (
    36  	// StorageKeyPattern the pattern of varible key stored in stateDB
    37  	/*
    38  		const fieldNameRe = /^[a-zA-Z_$][a-zA-Z0-9_]+$/;
    39  		var combineStorageMapKey = function (fieldName, key) {
    40  			return "@" + fieldName + "[" + key + "]";
    41  		};
    42  	*/
    43  	StorageKeyPattern = regexp.MustCompile("^@([a-zA-Z_$][a-zA-Z0-9_]+?)\\[(.*?)\\]$")
    44  	// DefaultDomainKey the default domain key
    45  	DefaultDomainKey = "_"
    46  	// ErrInvalidStorageKey invalid storage key error
    47  	ErrInvalidStorageKey = errors.New("invalid storage key")
    48  )
    49  
    50  // hashStorageKey return the key hash.
    51  // There are two kinds of key, the one is ItemKey, the other is Map-ItemKey.
    52  // ItemKey in SmartContract is used for object storage.
    53  // For example, the ItemKey for the statement "token.totalSupply = 1000" is "totalSupply".
    54  // Map-ItemKey in SmartContrat is used for Map storage.
    55  // For example, the Map-ItemKey for the statement "token.balances.set('addr1', 100)" is "@balances[addr1]".
    56  func parseStorageKey(key string) (string, string, error) {
    57  	matches := StorageKeyPattern.FindAllStringSubmatch(key, -1)
    58  	if matches == nil {
    59  		return DefaultDomainKey, key, nil
    60  	}
    61  
    62  	return matches[0][1], matches[0][2], nil
    63  }
    64  
    65  // StorageGetFunc export StorageGetFunc
    66  //export StorageGetFunc
    67  func StorageGetFunc(handler unsafe.Pointer, key *C.char, gasCnt *C.size_t) *C.char {
    68  	v8, storage := getEngineByStorageHandler(uint64(uintptr(handler)))
    69  	if storage == nil {
    70  		logging.VLog().Error("Failed to get storage handler.")
    71  		return nil
    72  	}
    73  
    74  	k := C.GoString(key)
    75  
    76  	// calculate Gas.
    77  	*gasCnt = C.size_t(0)
    78  
    79  	// test sync adaptation
    80  	// In Testnet, the tx `cadb*` in block 324997, the return data is nil.
    81  	if v8.ctx.tx.ChainID() == core.TestNetID &&
    82  		v8.ctx.block.Height() == 324997 &&
    83  		k == "size" &&
    84  		v8.ctx.tx.Hash().String() == "cadb0c6f7f6eb7d9a4f517aed00d4590bf4b80a9a89cf07dd71ec589b03fb9ae" {
    85  		return nil
    86  	}
    87  
    88  	domainKey, itemKey, err := parseStorageKey(k)
    89  	if err != nil {
    90  		logging.VLog().WithFields(logrus.Fields{
    91  			"handler": uint64(uintptr(handler)),
    92  			"key":     k,
    93  			"err":     err,
    94  		}).Debug("Invalid storage key.")
    95  		return nil
    96  	}
    97  
    98  	val, err := storage.Get(trie.HashDomains(domainKey, itemKey))
    99  	if err != nil {
   100  		if err != ErrKeyNotFound {
   101  			logging.VLog().WithFields(logrus.Fields{
   102  				"handler": uint64(uintptr(handler)),
   103  				"key":     k,
   104  				"err":     err,
   105  			}).Debug("StorageGetFunc get key failed.")
   106  		}
   107  		return nil
   108  	}
   109  
   110  	return C.CString(string(val))
   111  }
   112  
   113  // StoragePutFunc export StoragePutFunc
   114  //export StoragePutFunc
   115  func StoragePutFunc(handler unsafe.Pointer, key *C.char, value *C.char, gasCnt *C.size_t) int {
   116  	_, storage := getEngineByStorageHandler(uint64(uintptr(handler)))
   117  	if storage == nil {
   118  		logging.VLog().Error("Failed to get storage handler.")
   119  		return 1
   120  	}
   121  
   122  	k := C.GoString(key)
   123  	v := []byte(C.GoString(value))
   124  
   125  	// calculate Gas.
   126  	*gasCnt = C.size_t(len(k) + len(v))
   127  
   128  	domainKey, itemKey, err := parseStorageKey(k)
   129  	if err != nil {
   130  		logging.VLog().WithFields(logrus.Fields{
   131  			"handler": uint64(uintptr(handler)),
   132  			"key":     k,
   133  			"err":     err,
   134  		}).Debug("Invalid storage key.")
   135  		return 1
   136  	}
   137  
   138  	err = storage.Put(trie.HashDomains(domainKey, itemKey), v)
   139  	if err != nil && err != ErrKeyNotFound {
   140  		logging.VLog().WithFields(logrus.Fields{
   141  			"handler": uint64(uintptr(handler)),
   142  			"key":     k,
   143  			"err":     err,
   144  		}).Debug("StoragePutFunc put key failed.")
   145  		return 1
   146  	}
   147  
   148  	return 0
   149  }
   150  
   151  // StorageDelFunc export StorageDelFunc
   152  //export StorageDelFunc
   153  func StorageDelFunc(handler unsafe.Pointer, key *C.char, gasCnt *C.size_t) int {
   154  	_, storage := getEngineByStorageHandler(uint64(uintptr(handler)))
   155  	if storage == nil {
   156  		logging.VLog().Error("Failed to get storage handler.")
   157  		return 1
   158  	}
   159  
   160  	k := C.GoString(key)
   161  
   162  	// calculate Gas.
   163  	*gasCnt = C.size_t(0)
   164  
   165  	domainKey, itemKey, err := parseStorageKey(k)
   166  	if err != nil {
   167  		logging.VLog().WithFields(logrus.Fields{
   168  			"handler": uint64(uintptr(handler)),
   169  			"key":     k,
   170  			"err":     err,
   171  		}).Debug("invalid storage key.")
   172  		return 1
   173  	}
   174  
   175  	err = storage.Del(trie.HashDomains(domainKey, itemKey))
   176  	if err != nil && err != ErrKeyNotFound {
   177  		logging.VLog().WithFields(logrus.Fields{
   178  			"handler": uint64(uintptr(handler)),
   179  			"key":     k,
   180  			"err":     err,
   181  		}).Debug("StorageDelFunc del key failed.")
   182  		return 1
   183  	}
   184  
   185  	return 0
   186  }