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  }