github.com/aergoio/aergo@v1.3.1/contract/system_module.c (about) 1 #include <string.h> 2 #include <stdlib.h> 3 #include <time.h> 4 #include <stdint.h> 5 #include "vm.h" 6 #include "util.h" 7 #include "_cgo_export.h" 8 9 #define STATE_DB_KEY_PREFIX "_" 10 11 extern const int *getLuaExecContext(lua_State *L); 12 13 static int systemPrint(lua_State *L) 14 { 15 char *jsonValue; 16 int *service = (int *)getLuaExecContext(L); 17 18 jsonValue = lua_util_get_json_from_stack (L, 1, lua_gettop(L), true); 19 if (jsonValue == NULL) { 20 luaL_throwerror(L); 21 } 22 LuaPrint(L, service, jsonValue); 23 free(jsonValue); 24 return 0; 25 } 26 27 static char *getDbKey(lua_State *L, int *len) 28 { 29 size_t size; 30 char *key; 31 32 lua_pushvalue(L, 1); /* prefix key */ 33 lua_concat(L, 2); /* dbKey(prefix..key) */ 34 key = (char *)lua_tolstring(L, -1, &size); 35 *len = size; 36 return key; 37 } 38 39 int setItemWithPrefix(lua_State *L) 40 { 41 char *dbKey; 42 char *jsonValue; 43 int *service = (int *)getLuaExecContext(L); 44 char *errStr; 45 int keylen; 46 47 if (service == NULL) { 48 luaL_error(L, "cannot find execution context"); 49 } 50 51 luaL_checkstring(L, 1); 52 luaL_checkany(L, 2); 53 luaL_checkstring(L, 3); 54 dbKey = getDbKey(L, &keylen); 55 56 jsonValue = lua_util_get_json (L, 2, false); 57 if (jsonValue == NULL) { 58 luaL_throwerror(L); 59 } 60 61 if ((errStr = LuaSetDB(L, service, dbKey, keylen, jsonValue)) != NULL) { 62 free(jsonValue); 63 strPushAndRelease(L, errStr); 64 luaL_throwerror(L); 65 } 66 free(jsonValue); 67 68 return 0; 69 } 70 71 int setItem(lua_State *L) 72 { 73 luaL_checkstring(L, 1); 74 luaL_checkany(L, 2); 75 lua_pushstring(L, STATE_DB_KEY_PREFIX); 76 return setItemWithPrefix(L); 77 } 78 79 int getItemWithPrefix(lua_State *L) 80 { 81 char *dbKey; 82 int *service = (int *)getLuaExecContext(L); 83 char *jsonValue; 84 char *blkno = NULL; 85 struct LuaGetDB_return ret; 86 int keylen; 87 88 if (service == NULL) { 89 luaL_error(L, "cannot find execution context"); 90 } 91 luaL_checkstring(L, 1); 92 if(lua_gettop(L) == 2) { 93 luaL_checkstring(L, 2); 94 } 95 else if (lua_gettop(L) == 3) { 96 if (!lua_isnil(L, 2)) { 97 int type = lua_type(L,2); 98 if (type != LUA_TNUMBER && type != LUA_TSTRING) 99 luaL_error(L, "snap height permitted number or string type"); 100 blkno = (char *)lua_tostring(L, 2); 101 } 102 luaL_checkstring(L, 3); 103 } 104 dbKey = getDbKey(L, &keylen); 105 106 ret = LuaGetDB(L, service, dbKey, keylen, blkno); 107 if (ret.r1 != NULL) { 108 strPushAndRelease(L, ret.r1); 109 luaL_throwerror(L); 110 } 111 if (ret.r0 == NULL) 112 return 0; 113 114 minus_inst_count(L, strlen(ret.r0)); 115 if (lua_util_json_to_lua(L, ret.r0, false) != 0) { 116 strPushAndRelease(L, ret.r0); 117 luaL_error(L, "getItem error : can't convert %s", lua_tostring(L, -1)); 118 } 119 return 1; 120 } 121 122 int getItem(lua_State *L) 123 { 124 luaL_checkstring(L, 1); 125 lua_pushstring(L, STATE_DB_KEY_PREFIX); 126 if (lua_gettop(L) == 3) { 127 if (!lua_isnil(L, 2)) 128 luaL_checknumber(L, 2); 129 } 130 return getItemWithPrefix(L); 131 } 132 133 int delItemWithPrefix(lua_State *L) 134 { 135 char *dbKey; 136 int *service = (int *)getLuaExecContext(L); 137 char *jsonValue; 138 char *ret; 139 int keylen; 140 141 if (service == NULL) { 142 luaL_error(L, "cannot find execution context"); 143 } 144 luaL_checkstring(L, 1); 145 luaL_checkstring(L, 2); 146 dbKey = getDbKey(L, &keylen); 147 ret = LuaDelDB(L, service, dbKey, keylen); 148 if (ret != NULL) { 149 strPushAndRelease(L, ret); 150 luaL_throwerror(L); 151 } 152 return 0; 153 } 154 155 static int getSender(lua_State *L) 156 { 157 int *service = (int *)getLuaExecContext(L); 158 char *sender; 159 if (service == NULL) { 160 luaL_error(L, "cannot find execution context"); 161 } 162 sender = LuaGetSender(L, service); 163 strPushAndRelease(L, sender); 164 return 1; 165 } 166 167 static int getTxhash(lua_State *L) 168 { 169 int *service = (int *)getLuaExecContext(L); 170 char *hash; 171 if (service == NULL) { 172 luaL_error(L, "cannot find execution context"); 173 } 174 hash = LuaGetHash(L, service); 175 strPushAndRelease(L, hash); 176 return 1; 177 } 178 179 static int getBlockHeight(lua_State *L) 180 { 181 int *service = (int *)getLuaExecContext(L); 182 if (service == NULL) { 183 luaL_error(L, "cannot find execution context"); 184 } 185 lua_pushinteger(L, LuaGetBlockNo(L, service)); 186 return 1; 187 } 188 189 static int getTimestamp(lua_State *L) 190 { 191 int *service = (int *)getLuaExecContext(L); 192 if (service == NULL) { 193 luaL_error(L, "cannot find execution context"); 194 } 195 lua_pushinteger(L, LuaGetTimeStamp(L, service)); 196 return 1; 197 } 198 199 static int getContractID(lua_State *L) 200 { 201 int *service = (int *)getLuaExecContext(L); 202 char *id; 203 if (service == NULL) { 204 luaL_error(L, "cannot find execution context"); 205 } 206 id = LuaGetContractId(L, service); 207 strPushAndRelease(L, id); 208 return 1; 209 } 210 211 static int getCreator(lua_State *L) 212 { 213 int *service = (int *)getLuaExecContext(L); 214 struct LuaGetDB_return ret; 215 int keylen = 7; 216 217 if (service == NULL) { 218 luaL_error(L, "cannot find execution context"); 219 } 220 ret = LuaGetDB(L, service, "Creator", keylen, 0); 221 if (ret.r1 != NULL) { 222 strPushAndRelease(L, ret.r1); 223 luaL_throwerror(L); 224 } 225 if (ret.r0 == NULL) 226 return 0; 227 strPushAndRelease(L, ret.r0); 228 return 1; 229 } 230 231 static int getAmount(lua_State *L) 232 { 233 int *service = (int *)getLuaExecContext(L); 234 char *amount; 235 if (service == NULL) { 236 luaL_error(L, "cannot find execution context"); 237 } 238 amount = LuaGetAmount(L, service); 239 strPushAndRelease(L, amount); 240 return 1; 241 } 242 243 static int getOrigin(lua_State *L) 244 { 245 int *service = (int *)getLuaExecContext(L); 246 char *origin; 247 if (service == NULL) { 248 luaL_error(L, "cannot find execution context"); 249 } 250 origin = LuaGetOrigin(L, service); 251 strPushAndRelease(L, origin); 252 return 1; 253 } 254 255 static int getPrevBlockHash(lua_State *L) 256 { 257 int *service = (int *)getLuaExecContext(L); 258 char *hash; 259 if (service == NULL) { 260 luaL_error(L, "cannot find execution context"); 261 } 262 hash = LuaGetPrevBlockHash(L, service); 263 strPushAndRelease(L, hash); 264 return 1; 265 } 266 /* datetime-related functions from lib_os.c. time(NULL) is replaced by blocktime(L) */ 267 268 static void setfield(lua_State *L, const char *key, int value) 269 { 270 lua_pushinteger(L, value); 271 lua_setfield(L, -2, key); 272 } 273 274 static void setboolfield(lua_State *L, const char *key, int value) 275 { 276 if (value < 0) /* undefined? */ 277 return; /* does not set field */ 278 lua_pushboolean(L, value); 279 lua_setfield(L, -2, key); 280 } 281 282 static int getboolfield(lua_State *L, const char *key) 283 { 284 int res; 285 lua_getfield(L, -1, key); 286 res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); 287 lua_pop(L, 1); 288 return res; 289 } 290 291 static int getfield(lua_State *L, const char *key, int d) 292 { 293 int res; 294 lua_getfield(L, -1, key); 295 if (lua_isnumber(L, -1)) { 296 res = (int)lua_tointeger(L, -1); 297 } else { 298 if (d < 0) 299 luaL_error(L, "field " LUA_QS " missing in date table", key); 300 res = d; 301 } 302 lua_pop(L, 1); 303 return res; 304 } 305 306 static time_t blocktime(lua_State *L) 307 { 308 time_t t; 309 getTimestamp(L); 310 t = (time_t)lua_tointeger(L, -1); 311 lua_pop(L, 1); 312 return t; 313 } 314 315 static int os_date(lua_State *L) 316 { 317 const char *s = luaL_optstring(L, 1, "%c"); 318 time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, blocktime(L)); 319 struct tm *stm; 320 #if LJ_TARGET_POSIX 321 struct tm rtm; 322 #endif 323 if (*s == '!') { /* UTC? */ 324 s++; /* Skip '!' */ 325 } 326 #if LJ_TARGET_POSIX 327 stm = gmtime_r(&t, &rtm); 328 #else 329 stm = gmtime(&t); 330 #endif 331 if (stm == NULL) { /* Invalid date? */ 332 lua_pushnil(L); 333 } else if (strcmp(s, "*t") == 0) { 334 lua_createtable(L, 0, 9); /* 9 = number of fields */ 335 setfield(L, "sec", stm->tm_sec); 336 setfield(L, "min", stm->tm_min); 337 setfield(L, "hour", stm->tm_hour); 338 setfield(L, "day", stm->tm_mday); 339 setfield(L, "month", stm->tm_mon+1); 340 setfield(L, "year", stm->tm_year+1900); 341 setfield(L, "wday", stm->tm_wday+1); 342 setfield(L, "yday", stm->tm_yday+1); 343 setboolfield(L, "isdst", stm->tm_isdst); 344 } else { 345 char cc[3]; 346 luaL_Buffer b; 347 cc[0] = '%'; cc[2] = '\0'; 348 luaL_buffinit(L, &b); 349 for (; *s; s++) { 350 if (*s != '%' || *(s + 1) == '\0') { /* No conversion specifier? */ 351 luaL_addchar(&b, *s); 352 } else { 353 size_t reslen; 354 char buff[200]; /* Should be big enough for any conversion result. */ 355 cc[1] = *(++s); 356 if (cc[1] == 'c') { 357 reslen = strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", stm); 358 } else { 359 reslen = strftime(buff, sizeof(buff), cc, stm); 360 } 361 luaL_addlstring(&b, buff, reslen); 362 } 363 } 364 luaL_pushresult(&b); 365 } 366 return 1; 367 } 368 369 static int os_time(lua_State *L) 370 { 371 time_t t; 372 if (lua_isnoneornil(L, 1)) { 373 t = blocktime(L); 374 } else { 375 struct tm ts; 376 luaL_checktype(L, 1, LUA_TTABLE); 377 lua_settop(L, 1); /* make sure table is at the top */ 378 ts.tm_sec = getfield(L, "sec", 0); 379 ts.tm_min = getfield(L, "min", 0); 380 ts.tm_hour = getfield(L, "hour", 12); 381 ts.tm_mday = getfield(L, "day", -1); 382 ts.tm_mon = getfield(L, "month", -1) - 1; 383 ts.tm_year = getfield(L, "year", -1) - 1900; 384 ts.tm_isdst = getboolfield(L, "isdst"); 385 #if LJ_TARGET_POSIX 386 t = timegm(&ts); 387 #else 388 t = _mkgmtime(&ts); 389 #endif 390 } 391 if (t == (time_t)(-1)) 392 lua_pushnil(L); 393 else 394 lua_pushnumber(L, (lua_Number)t); 395 return 1; 396 } 397 398 static int os_difftime(lua_State *L) 399 { 400 lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), 401 (time_t)(luaL_optnumber(L, 2, (lua_Number)0)))); 402 return 1; 403 } 404 405 /* end of datetime functions */ 406 407 static int lua_random(lua_State *L) 408 { 409 int *service = (int *)getLuaExecContext(L); 410 int min, max; 411 412 if (service == NULL) { 413 luaL_error(L, "cannot find execution context"); 414 } 415 416 switch (lua_gettop(L)) { 417 case 1: 418 max = luaL_checkint(L, 1); 419 if (max < 1) { 420 luaL_error(L, "system.random: the maximum value must be greater than zero"); 421 } 422 lua_pushinteger(L, LuaRandomInt(1, max, *service)); 423 break; 424 case 2: 425 min = luaL_checkint(L, 1); 426 max = luaL_checkint(L, 2); 427 if (min < 1) { 428 luaL_error(L, "system.random: the minimum value must be greater than zero"); 429 } 430 if (min > max) { 431 luaL_error(L, "system.random: the maximum value must be greater than the minimum value"); 432 } 433 lua_pushinteger(L, LuaRandomInt(min, max, *service)); 434 break; 435 default: 436 luaL_error(L, "system.random: 1 or 2 arguments required"); 437 break; 438 } 439 440 return 1; 441 } 442 443 static int is_contract(lua_State *L) 444 { 445 char *contract; 446 int *service = (int *)getLuaExecContext(L); 447 struct LuaIsContract_return ret; 448 449 if (service == NULL) { 450 luaL_error(L, "cannot find execution context"); 451 } 452 453 contract = (char *)luaL_checkstring(L, 1); 454 ret = LuaIsContract(L, service, contract); 455 if (ret.r1 != NULL) { 456 strPushAndRelease(L, ret.r1); 457 luaL_throwerror(L); 458 } 459 if (ret.r0 == 0) 460 lua_pushboolean(L, false); 461 else 462 lua_pushboolean(L, true); 463 464 return 1; 465 } 466 467 static const luaL_Reg sys_lib[] = { 468 {"print", systemPrint}, 469 {"setItem", setItem}, 470 {"getItem", getItem}, 471 {"getSender", getSender}, 472 {"getCreator", getCreator}, 473 {"getTxhash", getTxhash}, 474 {"getBlockheight", getBlockHeight}, 475 {"getTimestamp", getTimestamp}, 476 {"getContractID", getContractID}, 477 {"getOrigin", getOrigin}, 478 {"getAmount", getAmount}, 479 {"getPrevBlockHash", getPrevBlockHash}, 480 {"date", os_date}, 481 {"time", os_time}, 482 {"difftime", os_difftime}, 483 {"random", lua_random}, 484 {"isContract", is_contract}, 485 {NULL, NULL} 486 }; 487 488 int luaopen_system(lua_State *L) 489 { 490 luaL_register(L, "system", sys_lib); 491 lua_pop(L, 1); 492 return 1; 493 }