github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/module.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 "fmt" 25 "regexp" 26 "strings" 27 "unsafe" 28 29 "github.com/nebulasio/go-nebulas/core" 30 "github.com/nebulasio/go-nebulas/util/logging" 31 "github.com/sirupsen/logrus" 32 ) 33 34 // const 35 const ( 36 JSLibRootName = "lib/" 37 JSLibRootNameLen = 4 38 ) 39 40 var ( 41 pathRe = regexp.MustCompile("^\\.{0,2}/") 42 ) 43 44 // Module module structure. 45 type Module struct { 46 id string 47 source string 48 lineOffset int 49 } 50 51 // Modules module maps. 52 type Modules map[string]*Module 53 54 // NewModules create new modules and return it. 55 func NewModules() Modules { 56 return make(Modules, 1) 57 } 58 59 // NewModule create new module and return it. 60 func NewModule(id, source string, lineOffset int) *Module { 61 if !pathRe.MatchString(id) { 62 id = fmt.Sprintf("lib/%s", id) 63 } 64 id = reformatModuleID(id) 65 66 return &Module{ 67 id: id, 68 source: source, 69 lineOffset: lineOffset, 70 } 71 } 72 73 // Add add source to module. 74 func (ms Modules) Add(m *Module) { 75 ms[m.id] = m 76 } 77 78 // Get get module from Modules by id. 79 func (ms Modules) Get(id string) *Module { 80 return ms[id] 81 } 82 83 // RequireDelegateFunc delegate func for require. 84 //export RequireDelegateFunc 85 func RequireDelegateFunc(handler unsafe.Pointer, filename *C.char, lineOffset *C.size_t) *C.char { 86 id := C.GoString(filename) 87 88 e := getEngineByEngineHandler(handler) 89 if e == nil { 90 logging.VLog().WithFields(logrus.Fields{ 91 "filename": id, 92 }).Error("require delegate handler does not found.") 93 return nil 94 } 95 96 module := e.modules.Get(id) 97 if module == nil { 98 return nil 99 } 100 101 *lineOffset = C.size_t(module.lineOffset) 102 cSource := C.CString(module.source) 103 return cSource 104 } 105 106 // AttachLibVersionDelegateFunc delegate func for lib version choose 107 //export AttachLibVersionDelegateFunc 108 func AttachLibVersionDelegateFunc(handler unsafe.Pointer, require *C.char) *C.char { 109 libname := C.GoString(require) 110 e := getEngineByEngineHandler(handler) 111 if e == nil { 112 logging.VLog().WithFields(logrus.Fields{ 113 "libname": libname, 114 }).Error("delegate handler does not found.") 115 return nil 116 } 117 if len(libname) == 0 { 118 logging.VLog().Error("libname is empty.") 119 return nil 120 } 121 122 if e.ctx == nil { 123 logging.VLog().WithFields(logrus.Fields{ 124 "libname": libname, 125 }).Error("e.context is nil.") 126 return nil 127 } 128 if e.ctx.block == nil { 129 logging.VLog().WithFields(logrus.Fields{ 130 "libname": libname, 131 }).Error("e.context.block is nil.") 132 return nil 133 } 134 135 // for instruction_counter.js 136 if strings.HasSuffix(libname, "instruction_counter.js") { 137 v := core.GetNearestInstructionCounterVersionAtHeight(e.ctx.block.Height()) 138 if len(v) == 0 { 139 logging.VLog().WithFields(logrus.Fields{ 140 "libname": libname, 141 "blockHeight": e.ctx.block.Height(), 142 }).Error("instruction_counter version not found.") 143 return nil 144 } 145 return C.CString(JSLibRootName + v + libname[JSLibRootNameLen-1:]) 146 } 147 148 // block after core.V8JSLibVersionControlHeight, inclusive 149 if core.V8JSLibVersionControlAtHeight(e.ctx.block.Height()) { 150 if e.ctx.contract == nil { 151 logging.VLog().WithFields(logrus.Fields{ 152 "libname": libname, 153 "height": e.ctx.block.Height(), 154 }).Error("e.context.contract is nil.") 155 return nil 156 } 157 if e.ctx.contract.ContractMeta() == nil { 158 /* 159 logging.VLog().WithFields(logrus.Fields{ 160 "libname": libname, 161 "height": e.ctx.block.Height(), 162 }).Debug("e.context.contract.ContractMeta is nil.") 163 */ 164 return attachDefaultVersionLib(libname) 165 } 166 cv := e.ctx.contract.ContractMeta().Version 167 168 if len(cv) == 0 { 169 logging.VLog().WithFields(logrus.Fields{ 170 "libname": libname, 171 "height": e.ctx.block.Height(), 172 }).Error("contract deploy lib version is empty.") 173 return nil 174 } 175 176 if !strings.HasPrefix(libname, JSLibRootName) || strings.Contains(libname, "../") { 177 logging.VLog().WithFields(logrus.Fields{ 178 "libname": libname, 179 "height": e.ctx.block.Height(), 180 "deployVersion": cv, 181 }).Error("invalid require path.") 182 return nil 183 } 184 185 ver := core.FindLastNearestLibVersion(cv, libname[JSLibRootNameLen:]) 186 if len(ver) == 0 { 187 logging.VLog().WithFields(logrus.Fields{ 188 "libname": libname, 189 "deployLibVer": cv, 190 }).Error("lib version not found.") 191 return nil 192 } 193 194 return C.CString(JSLibRootName + ver + libname[JSLibRootNameLen-1:]) 195 } 196 197 return attachDefaultVersionLib(libname) 198 } 199 200 func attachDefaultVersionLib(libname string) *C.char { 201 // block created before core.V8JSLibVersionControlHeight, default lib version: 1.0.0 202 if !strings.HasPrefix(libname, JSLibRootName) { 203 if strings.HasPrefix(libname, "/") { 204 libname = "lib" + libname 205 } else { 206 libname = JSLibRootName + libname 207 } 208 } 209 return C.CString(JSLibRootName + core.DefaultV8JSLibVersion + libname[JSLibRootNameLen-1:]) 210 } 211 212 func reformatModuleID(id string) string { 213 paths := make([]string, 0) 214 for _, p := range strings.Split(id, "/") { 215 if len(p) == 0 || strings.Compare(".", p) == 0 { 216 continue 217 } 218 if strings.Compare("..", p) == 0 { 219 if len(paths) > 0 { 220 paths = paths[:len(paths)-1] 221 continue 222 } 223 } 224 paths = append(paths, p) 225 } 226 227 return strings.Join(paths, "/") 228 }