github.com/aergoio/aergo@v1.3.1/contract/contract_module.c (about) 1 #include <string.h> 2 #include <stdlib.h> 3 #include "vm.h" 4 #include "util.h" 5 #include "lgmp.h" 6 #include "_cgo_export.h" 7 8 extern const int *getLuaExecContext(lua_State *L); 9 10 static const char *contract_str = "contract"; 11 static const char *call_str = "call"; 12 static const char *delegatecall_str = "delegatecall"; 13 static const char *deploy_str = "deploy"; 14 static const char *amount_str = "amount_value"; 15 static const char *fee_str = "fee"; 16 17 static void set_call_obj(lua_State *L, const char* obj_name) 18 { 19 lua_getglobal(L, contract_str); 20 lua_getfield(L, -1, obj_name); 21 } 22 23 static void reset_amount_info (lua_State *L) 24 { 25 lua_pushnil(L); 26 lua_setfield(L, 1, amount_str); 27 lua_pushnil(L); 28 lua_setfield(L, 1, fee_str); 29 } 30 31 static int set_value(lua_State *L, const char *str) 32 { 33 set_call_obj(L, str); 34 if (lua_isnil(L, 1)) { 35 return 1; 36 } 37 switch(lua_type(L, 1)) { 38 case LUA_TNUMBER: { 39 const char *str = lua_tostring(L, 1); 40 lua_pushstring(L, str); 41 break; 42 } 43 case LUA_TSTRING: 44 lua_pushvalue(L, 1); 45 break; 46 case LUA_TUSERDATA: { 47 char *str = lua_get_bignum_str(L, 1); 48 if (str == NULL) { 49 luaL_error(L, "not enough memory"); 50 } 51 lua_pushstring(L, str); 52 free (str); 53 break; 54 } 55 default: 56 luaL_error(L, "invalid input"); 57 } 58 lua_setfield(L, -2, amount_str); 59 60 return 1; 61 } 62 63 static int set_gas(lua_State *L, const char *str) 64 { 65 lua_Integer gas; 66 67 set_call_obj(L, str); 68 if (lua_isnil(L, 1)) { 69 return 1; 70 } 71 gas = luaL_checkinteger(L, 1); 72 if (gas < 0) { 73 luaL_error(L, "invalid number"); 74 } 75 lua_pushinteger(L, gas); 76 lua_setfield(L, -2, fee_str); 77 78 return 1; 79 } 80 81 static int call_value(lua_State *L) 82 { 83 return set_value(L, call_str); 84 } 85 86 static int call_gas(lua_State *L) 87 { 88 return set_gas(L, call_str); 89 } 90 91 static int moduleCall(lua_State *L) 92 { 93 char *contract; 94 char *fname; 95 char *json_args; 96 struct LuaCallContract_return ret; 97 int *service = (int *)getLuaExecContext(L); 98 lua_Integer gas; 99 char *amount; 100 101 if (service == NULL) { 102 reset_amount_info(L); 103 luaL_error(L, "cannot find execution context"); 104 } 105 106 lua_getfield(L, 1, amount_str); 107 if (lua_isnil(L, -1)) 108 amount = NULL; 109 else 110 amount = (char *)luaL_checkstring(L, -1); 111 112 lua_getfield(L, 1, fee_str); 113 if (lua_isnil(L, -1)) 114 gas = 0; 115 else 116 gas = luaL_checkinteger(L, -1); 117 118 lua_pop(L, 2); 119 contract = (char *)luaL_checkstring(L, 2); 120 fname = (char *)luaL_checkstring(L, 3); 121 json_args = lua_util_get_json_from_stack (L, 4, lua_gettop(L), false); 122 if (json_args == NULL) { 123 reset_amount_info(L); 124 luaL_throwerror(L); 125 } 126 127 ret = LuaCallContract(L, service, contract, fname, json_args, amount, gas); 128 if (ret.r1 != NULL) { 129 free(json_args); 130 reset_amount_info(L); 131 strPushAndRelease(L, ret.r1); 132 luaL_throwerror(L); 133 } 134 free(json_args); 135 reset_amount_info(L); 136 return ret.r0; 137 } 138 139 static int delegate_call_gas(lua_State *L) 140 { 141 return set_gas(L, delegatecall_str); 142 } 143 144 static int moduleDelegateCall(lua_State *L) 145 { 146 char *contract; 147 char *fname; 148 char *json_args; 149 struct LuaDelegateCallContract_return ret; 150 int *service = (int *)getLuaExecContext(L); 151 lua_Integer gas; 152 153 if (service == NULL) { 154 reset_amount_info(L); 155 luaL_error(L, "cannot find execution context"); 156 } 157 158 lua_getfield(L, 1, fee_str); 159 if (lua_isnil(L, -1)) 160 gas = 0; 161 else 162 gas = luaL_checkinteger(L, -1); 163 164 lua_pop(L, 1); 165 contract = (char *)luaL_checkstring(L, 2); 166 fname = (char *)luaL_checkstring(L, 3); 167 json_args = lua_util_get_json_from_stack (L, 4, lua_gettop(L), false); 168 if (json_args == NULL) { 169 reset_amount_info(L); 170 luaL_throwerror(L); 171 } 172 ret = LuaDelegateCallContract(L, service, contract, fname, json_args, gas); 173 if (ret.r1 != NULL) { 174 free(json_args); 175 reset_amount_info(L); 176 strPushAndRelease(L, ret.r1); 177 luaL_throwerror(L); 178 } 179 free(json_args); 180 reset_amount_info(L); 181 182 return ret.r0; 183 } 184 185 static int moduleSend(lua_State *L) 186 { 187 char *contract; 188 char *errStr; 189 int *service = (int *)getLuaExecContext(L); 190 char *amount; 191 bool needfree = false; 192 193 if (service == NULL) { 194 luaL_error(L, "cannot find execution context"); 195 } 196 contract = (char *)luaL_checkstring(L, 1); 197 if (lua_isnil(L, 2)) 198 return 0; 199 200 switch(lua_type(L, 2)) { 201 case LUA_TNUMBER: 202 amount = (char *)lua_tostring(L, 2); 203 break; 204 case LUA_TSTRING: 205 amount = (char *)lua_tostring(L, 2); 206 break; 207 case LUA_TUSERDATA: 208 amount = lua_get_bignum_str(L, 2); 209 if (amount == NULL) { 210 luaL_error(L, "not enough memory"); 211 } 212 needfree = true; 213 break; 214 default: 215 luaL_error(L, "invalid input"); 216 } 217 errStr = LuaSendAmount(L, service, contract, amount); 218 if (needfree) 219 free(amount); 220 if (errStr != NULL) { 221 strPushAndRelease(L, errStr); 222 luaL_throwerror(L); 223 } 224 return 0; 225 } 226 227 static int moduleBalance(lua_State *L) 228 { 229 char *contract; 230 int *service = (int *)getLuaExecContext(L); 231 lua_Integer amount; 232 struct LuaGetBalance_return balance; 233 234 if (service == NULL) { 235 luaL_error(L, "cannot find execution context"); 236 } 237 238 if (lua_gettop(L) == 0 || lua_isnil(L, 1)) 239 contract = NULL; 240 else { 241 contract = (char *)luaL_checkstring(L, 1); 242 } 243 244 balance = LuaGetBalance(L, service, contract); 245 if (balance.r1 != NULL) { 246 strPushAndRelease(L, balance.r1); 247 luaL_throwerror(L); 248 } 249 250 strPushAndRelease(L, balance.r0); 251 return 1; 252 } 253 254 static int modulePcall(lua_State *L) 255 { 256 int argc = lua_gettop(L) - 1; 257 int *service = (int *)getLuaExecContext(L); 258 struct LuaSetRecoveryPoint_return start_seq; 259 int ret; 260 261 if (service == NULL) { 262 luaL_error(L, "cannot find execution context"); 263 } 264 265 start_seq = LuaSetRecoveryPoint(L, service); 266 if (start_seq.r0 < 0) { 267 strPushAndRelease(L, start_seq.r1); 268 luaL_throwerror(L); 269 } 270 271 if ((ret = lua_pcall(L, argc, LUA_MULTRET, 0)) != 0) { 272 if (ret == LUA_ERRMEM) { 273 luaL_throwerror(L); 274 } 275 lua_pushboolean(L, false); 276 lua_insert(L, 1); 277 if (start_seq.r0 > 0) { 278 char *errStr = LuaClearRecovery(L, service, start_seq.r0, true); 279 if (errStr != NULL) { 280 strPushAndRelease(L, errStr); 281 luaL_throwerror(L); 282 } 283 } 284 return 2; 285 } 286 lua_pushboolean(L, true); 287 lua_insert(L, 1); 288 if (start_seq.r0 == 1) { 289 char *errStr = LuaClearRecovery(L, service, start_seq.r0, false); 290 if (errStr != NULL) { 291 strPushAndRelease(L, errStr); 292 luaL_throwerror(L); 293 } 294 } 295 return lua_gettop(L); 296 } 297 298 static int deploy_value(lua_State *L) 299 { 300 return set_value(L, deploy_str); 301 } 302 303 static int moduleDeploy(lua_State *L) 304 { 305 char *contract; 306 char *fname; 307 char *json_args; 308 struct LuaDeployContract_return ret; 309 int *service = (int *)getLuaExecContext(L); 310 char *amount; 311 312 if (service == NULL) { 313 reset_amount_info(L); 314 luaL_error(L, "cannot find execution context"); 315 } 316 317 lua_getfield(L, 1, amount_str); 318 if (lua_isnil(L, -1)) 319 amount = NULL; 320 else 321 amount = (char *)luaL_checkstring(L, -1); 322 lua_pop(L, 1); 323 contract = (char *)luaL_checkstring(L, 2); 324 json_args = lua_util_get_json_from_stack (L, 3, lua_gettop(L), false); 325 if (json_args == NULL) { 326 reset_amount_info(L); 327 luaL_throwerror(L); 328 } 329 330 ret = LuaDeployContract(L, service, contract, json_args, amount); 331 if (ret.r0 < 0) { 332 free(json_args); 333 reset_amount_info(L); 334 strPushAndRelease(L, ret.r1); 335 luaL_throwerror(L); 336 } 337 free(json_args); 338 reset_amount_info(L); 339 strPushAndRelease(L, ret.r1); 340 if (ret.r0 > 1) 341 lua_insert(L, -ret.r0); 342 343 return ret.r0; 344 } 345 346 static int moduleEvent(lua_State *L) 347 { 348 char *event_name; 349 char *json_args; 350 int *service = (int *)getLuaExecContext(L); 351 char *errStr; 352 353 if (service == NULL) { 354 luaL_error(L, "cannot find execution context"); 355 } 356 357 event_name = (char *)luaL_checkstring(L, 1); 358 json_args = lua_util_get_json_from_stack (L, 2, lua_gettop(L), false); 359 if (json_args == NULL) { 360 luaL_throwerror(L); 361 } 362 errStr = LuaEvent(L, service, event_name, json_args); 363 if (errStr != NULL) { 364 strPushAndRelease(L, errStr); 365 luaL_throwerror(L); 366 } 367 free(json_args); 368 return 0; 369 } 370 371 static int governance(lua_State *L, char type) { 372 char *ret; 373 int *service = (int *)getLuaExecContext(L); 374 char *arg; 375 bool needfree = false; 376 377 if (service == NULL) { 378 luaL_error(L, "cannot find execution context"); 379 } 380 381 if (type != 'V') { 382 if (lua_isnil(L, 1)) 383 return 0; 384 385 switch(lua_type(L, 1)) { 386 case LUA_TNUMBER: 387 arg = (char *)lua_tostring(L, 1); 388 break; 389 case LUA_TSTRING: 390 arg = (char *)lua_tostring(L, 1); 391 break; 392 case LUA_TUSERDATA: 393 arg = lua_get_bignum_str(L, 1); 394 if (arg == NULL) { 395 luaL_error(L, "not enough memory"); 396 } 397 needfree = true; 398 break; 399 default: 400 luaL_error(L, "invalid input"); 401 } 402 } 403 else { 404 arg = lua_util_get_json_from_stack (L, 1, lua_gettop(L), false); 405 if (arg == NULL) 406 luaL_throwerror(L); 407 if (strlen(arg) == 0) { 408 free(arg); 409 luaL_error(L, "invalid input"); 410 } 411 needfree = true; 412 } 413 ret = LuaGovernance(L, service, type, arg); 414 if (needfree) 415 free(arg); 416 if (ret != NULL) { 417 strPushAndRelease(L, ret); 418 luaL_throwerror(L); 419 } 420 return 0; 421 } 422 423 static int moduleStake(lua_State *L) { 424 return governance(L, 'S'); 425 } 426 427 static int moduleUnstake(lua_State *L) { 428 return governance(L, 'U'); 429 } 430 431 static int moduleVote(lua_State *L) { 432 return governance(L, 'V'); 433 } 434 435 static const luaL_Reg call_methods[] = { 436 {"value", call_value}, 437 {"amount", call_value}, 438 {"gas", call_gas}, 439 {NULL, NULL} 440 }; 441 442 static const luaL_Reg call_meta[] = { 443 {"__call", moduleCall}, 444 {NULL, NULL} 445 }; 446 447 static const luaL_Reg delegate_call_methods[] = { 448 {"gas", delegate_call_gas}, 449 {NULL, NULL} 450 }; 451 452 static const luaL_Reg delegate_call_meta[] = { 453 {"__call", moduleDelegateCall}, 454 {NULL, NULL} 455 }; 456 457 static const luaL_Reg deploy_call_methods[] = { 458 {"value", deploy_value}, 459 {"amount", deploy_value}, 460 {NULL, NULL} 461 }; 462 463 static const luaL_Reg deploy_call_meta[] = { 464 {"__call", moduleDeploy}, 465 {NULL, NULL} 466 }; 467 468 static const luaL_Reg contract_lib[] = { 469 {"balance", moduleBalance}, 470 {"send", moduleSend}, 471 {"pcall", modulePcall}, 472 {"event", moduleEvent}, 473 {"stake", moduleStake}, 474 {"unstake", moduleUnstake}, 475 {"vote", moduleVote}, 476 {NULL, NULL} 477 }; 478 479 int luaopen_contract(lua_State *L) 480 { 481 luaL_register(L, contract_str, contract_lib); 482 lua_createtable(L, 0, 3); 483 luaL_register(L, NULL, call_methods); 484 lua_createtable(L, 0, 1); 485 luaL_register(L, NULL, call_meta); 486 lua_setmetatable(L, -2); 487 lua_setfield(L, -2, call_str); 488 489 lua_createtable(L, 0, 1); 490 luaL_register(L, NULL, delegate_call_methods); 491 lua_createtable(L, 0, 1); 492 luaL_register(L, NULL, delegate_call_meta); 493 lua_setmetatable(L, -2); 494 lua_setfield(L, -2, delegatecall_str); 495 496 lua_createtable(L, 0, 2); 497 luaL_register(L, NULL, deploy_call_methods); 498 lua_createtable(L, 0, 1); 499 luaL_register(L, NULL, deploy_call_meta); 500 lua_setmetatable(L, -2); 501 lua_setfield(L, -2, deploy_str); 502 lua_pop(L, 1); 503 return 1; 504 }