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 }