github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/v8/lib/blockchain.cc (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
     6  // modify 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
    17  // <http://www.gnu.org/licenses/>.
    18  //
    19  
    20  #include "blockchain.h"
    21  #include "global.h"
    22  #include "../engine.h"
    23  #include "global.h"
    24  #include "instruction_counter.h"
    25  #include "logger.h"
    26  #include "limits.h"
    27  
    28  static GetTxByHashFunc sGetTxByHash = NULL;
    29  static GetAccountStateFunc sGetAccountState = NULL;
    30  static TransferFunc sTransfer = NULL;
    31  static VerifyAddressFunc sVerifyAddress = NULL;
    32  static GetPreBlockHashFunc sGetPreBlockHash = NULL;
    33  static GetPreBlockSeedFunc sGetPreBlockSeed = NULL;
    34  static GetContractSourceFunc sGetContractSource = NULL;
    35  static InnerContractFunc sRunInnerContract = NULL;
    36  static GetLatestNebulasRankFunc sGetLatestNR = NULL;
    37  static GetLatestNebulasRankSummaryFunc sGetLatestNRSum = NULL;
    38  
    39  void InitializeBlockchain(GetTxByHashFunc getTx, GetAccountStateFunc getAccount,
    40                            TransferFunc transfer,
    41                            VerifyAddressFunc verifyAddress,
    42                            GetPreBlockHashFunc getPreBlockHash,
    43                            GetPreBlockSeedFunc getPreBlockSeed,
    44                            GetContractSourceFunc contractSource,
    45                            InnerContractFunc rMultContract,
    46                            GetLatestNebulasRankFunc getLatestNR,
    47                            GetLatestNebulasRankSummaryFunc getLatestNRSum) {
    48    sGetTxByHash = getTx;
    49    sGetAccountState = getAccount;
    50    sTransfer = transfer;
    51    sVerifyAddress = verifyAddress;
    52    sGetPreBlockHash = getPreBlockHash;
    53    sGetPreBlockSeed = getPreBlockSeed;
    54    sGetContractSource = contractSource;
    55    sRunInnerContract = rMultContract;
    56    sGetLatestNR = getLatestNR;
    57    sGetLatestNRSum = getLatestNRSum;
    58  }
    59  
    60  void NewBlockchainInstance(Isolate *isolate, Local<Context> context,
    61                             void *handler, uint64_t build_flag) {
    62    Local<ObjectTemplate> blockTpl = ObjectTemplate::New(isolate);
    63    blockTpl->SetInternalFieldCount(1);
    64  
    65    /* disable getTransactionByHash() function.
    66      blockTpl->Set(String::NewFromUtf8(isolate, "getTransactionByHash"),
    67                    FunctionTemplate::New(isolate, GetTransactionByHashCallback),
    68                    static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
    69                                                   PropertyAttribute::ReadOnly));
    70    */
    71  
    72    blockTpl->Set(String::NewFromUtf8(isolate, "getAccountState"),
    73                  FunctionTemplate::New(isolate, GetAccountStateCallback),
    74                  static_cast<PropertyAttribute>(PropertyAttribute::DontDelete|
    75                                                  PropertyAttribute::ReadOnly));
    76  
    77  
    78    blockTpl->Set(String::NewFromUtf8(isolate, "transfer"),
    79                  FunctionTemplate::New(isolate, TransferCallback),
    80                  static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
    81                                                 PropertyAttribute::ReadOnly));
    82  
    83    blockTpl->Set(String::NewFromUtf8(isolate, "verifyAddress"),
    84                  FunctionTemplate::New(isolate, VerifyAddressCallback),
    85                  static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
    86                                                 PropertyAttribute::ReadOnly));
    87    if (BUILD_BLOCKCHAIN_GET_RUN_SOURCE == (build_flag & BUILD_BLOCKCHAIN_GET_RUN_SOURCE)) {
    88      // printf("load getContractSource\n");
    89      blockTpl->Set(String::NewFromUtf8(isolate, "getContractSource"),
    90                  FunctionTemplate::New(isolate, GetContractSourceCallback),
    91                  static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
    92                                                 PropertyAttribute::ReadOnly | 
    93                                                 PropertyAttribute::DontEnum));
    94    }
    95    
    96    if (BUILD_BLOCKCHAIN_RUN_CONTRACT == (build_flag & BUILD_BLOCKCHAIN_RUN_CONTRACT)) {
    97      // printf("load runContractSource\n");
    98      blockTpl->Set(String::NewFromUtf8(isolate, "runContractSource"),
    99                  FunctionTemplate::New(isolate, RunInnerContractSourceCallBack),
   100                  static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
   101                                                 PropertyAttribute::ReadOnly |
   102                                                 PropertyAttribute::DontEnum));
   103    }
   104    
   105  
   106    blockTpl->Set(String::NewFromUtf8(isolate, "getPreBlockHash"),
   107                FunctionTemplate::New(isolate, GetPreBlockHashCallback),
   108                static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
   109                                                PropertyAttribute::ReadOnly));
   110  
   111    blockTpl->Set(String::NewFromUtf8(isolate, "getPreBlockSeed"),
   112                FunctionTemplate::New(isolate, GetPreBlockSeedCallback),
   113                static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
   114                                                PropertyAttribute::ReadOnly));
   115  
   116    blockTpl->Set(String::NewFromUtf8(isolate, "getLatestNebulasRank"),
   117                FunctionTemplate::New(isolate, GetLatestNebulasRankCallback),
   118                static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
   119                                                PropertyAttribute::ReadOnly));
   120  
   121    blockTpl->Set(String::NewFromUtf8(isolate, "getLatestNebulasRankSummary"),
   122                FunctionTemplate::New(isolate, GetLatestNebulasRankSummaryCallback),
   123                static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
   124                                                PropertyAttribute::ReadOnly));
   125  
   126  
   127    Local<Object> instance = blockTpl->NewInstance(context).ToLocalChecked();
   128    instance->SetInternalField(0, External::New(isolate, handler));
   129  
   130    context->Global()->DefineOwnProperty(
   131        context, String::NewFromUtf8(isolate, "_native_blockchain"), instance,
   132        static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
   133                                       PropertyAttribute::ReadOnly));
   134  }
   135  
   136  // GetTransactionByHashCallback
   137  void GetTransactionByHashCallback(const FunctionCallbackInfo<Value> &info) {
   138    Isolate *isolate = info.GetIsolate();
   139    Local<Object> thisArg = info.Holder();
   140    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   141  
   142    if (info.Length() != 1) {
   143      isolate->ThrowException(String::NewFromUtf8(
   144          isolate, "Blockchain.getTransactionByHash() requires only 1 argument"));
   145      return;
   146    }
   147  
   148    Local<Value> key = info[0];
   149    if (!key->IsString()) {
   150      isolate->ThrowException(String::NewFromUtf8(isolate, "key must be string"));
   151      return;
   152    }
   153  
   154    size_t cnt = 0;
   155  
   156    char *value =
   157        sGetTxByHash(handler->Value(), *String::Utf8Value(key->ToString()), &cnt);
   158    if (value == NULL) {
   159      info.GetReturnValue().SetNull();
   160    } else {
   161      info.GetReturnValue().Set(String::NewFromUtf8(isolate, value));
   162      free(value);
   163    }
   164  
   165    // record storage usage.
   166    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   167  }
   168  
   169  // GetAccountStateCallback
   170  void GetAccountStateCallback(const FunctionCallbackInfo<Value> &info) {
   171    int err = NVM_SUCCESS;
   172    Isolate *isolate = info.GetIsolate();
   173    if (NULL == isolate) {
   174      LogFatalf("Unexpected error: failed to get ioslate");
   175    }
   176    Local<Object> thisArg = info.Holder();
   177    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));//TODO:
   178  
   179    if (info.Length() != 1) {
   180      isolate->ThrowException(String::NewFromUtf8(
   181          isolate, "Blockchain.getAccountState() requires only 1 argument"));
   182      return;
   183    }
   184  
   185    Local<Value> key = info[0];
   186    if (!key->IsString()) {
   187      isolate->ThrowException(String::NewFromUtf8(isolate, "Blockchain.getAccountState(), argument must be a string"));
   188      return;
   189    }
   190  
   191  
   192    size_t cnt = 0;
   193    char *result = NULL;
   194    char *exceptionInfo = NULL;
   195    err = sGetAccountState(handler->Value(), *String::Utf8Value(key->ToString()), &cnt, &result, &exceptionInfo);
   196  
   197    DEAL_ERROR_FROM_GOLANG(err);
   198  
   199    if (result != NULL) {
   200      free(result);
   201      result = NULL;
   202    }
   203  
   204    if (exceptionInfo != NULL) {
   205      free(exceptionInfo);
   206      exceptionInfo = NULL;
   207    }
   208  
   209    // record storage usage.
   210    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   211  }
   212  
   213  // TransferCallback
   214  void TransferCallback(const FunctionCallbackInfo<Value> &info) {
   215    Isolate *isolate = info.GetIsolate();
   216    Local<Object> thisArg = info.Holder();
   217    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   218  
   219    if (info.Length() != 2) {
   220      isolate->ThrowException(
   221          String::NewFromUtf8(isolate, "Blockchain.send() requires 2 arguments"));
   222      return;
   223    }
   224  
   225    Local<Value> address = info[0];
   226    if (!address->IsString()) {
   227      isolate->ThrowException(
   228          String::NewFromUtf8(isolate, "address must be string"));
   229      return;
   230    }
   231  
   232    Local<Value> amount = info[1];
   233    if (!amount->IsString()) {
   234      isolate->ThrowException(
   235          String::NewFromUtf8(isolate, "value must be string"));
   236      return;
   237    }
   238  
   239    size_t cnt = 0;
   240  
   241    int ret = sTransfer(handler->Value(), *String::Utf8Value(address->ToString()),
   242                        *String::Utf8Value(amount->ToString()), &cnt);
   243    info.GetReturnValue().Set(ret);
   244  
   245    // record storage usage.
   246    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   247  }
   248  
   249  // VerifyAddressCallback
   250  void VerifyAddressCallback(const FunctionCallbackInfo<Value> &info) {
   251    Isolate *isolate = info.GetIsolate();
   252    Local<Object> thisArg = info.Holder();
   253    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   254  
   255    if (info.Length() != 1) {
   256      isolate->ThrowException(String::NewFromUtf8(
   257          isolate, "Blockchain.verifyAddress() requires 1 argument"));
   258      return;
   259    }
   260  
   261    Local<Value> address = info[0];
   262    if (!address->IsString()) {
   263      isolate->ThrowException(
   264          String::NewFromUtf8(isolate, "address must be string"));
   265      return;
   266    }
   267  
   268    size_t cnt = 0;
   269  
   270    int ret = sVerifyAddress(handler->Value(),
   271                             *String::Utf8Value(address->ToString()), &cnt);
   272    info.GetReturnValue().Set(ret);
   273  
   274    // record storage usage.
   275    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   276  }
   277  
   278  // GetPreBlockHashCallBack
   279  void GetPreBlockHashCallback(const FunctionCallbackInfo<Value> &info) {
   280    int err = NVM_SUCCESS;
   281    Isolate *isolate = info.GetIsolate();
   282    if (NULL == isolate) {
   283      LogFatalf("Unexpected error: failed to get isolate");
   284    }
   285    Local<Object> thisArg = info.Holder();
   286    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   287  
   288    if (info.Length() != 1) {
   289      isolate->ThrowException(String::NewFromUtf8(
   290          isolate, "Blockchain.GetPreBlockHash() requires 1 arguments"));
   291      return;
   292    } 
   293  
   294    Local<Value> offset = info[0];
   295    if (!offset->IsNumber()) {
   296      isolate->ThrowException(
   297          String::NewFromUtf8(isolate, "Blockchain.GetPreBlockHash(), the argument must be a number")); 
   298      return;
   299    }
   300  
   301    double v = Number::Cast(*offset)->Value();
   302    if (v > ULLONG_MAX || v <= 0) {
   303      isolate->ThrowException(
   304          String::NewFromUtf8(isolate, "Blockchain.GetPreBlockHash(), argument out of range"));
   305      return;
   306    }
   307  
   308    if (v != (double)(unsigned long long)v) {
   309          isolate->ThrowException(
   310          String::NewFromUtf8(isolate, "Blockchain.GetPreBlockHash(), argument must be integer"));
   311      return;
   312    }
   313  
   314    size_t cnt = 0;
   315    char *result = NULL;
   316    char *exceptionInfo = NULL;
   317    err = sGetPreBlockHash(handler->Value(), (unsigned long long)(v), &cnt, &result, &exceptionInfo);
   318  
   319    DEAL_ERROR_FROM_GOLANG(err);  
   320  
   321    if (result != NULL) {
   322      free(result);
   323      result = NULL;
   324    }
   325  
   326    if (exceptionInfo != NULL) {
   327      free(exceptionInfo);
   328      exceptionInfo = NULL;
   329    }
   330  
   331    // record storage usage.
   332    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   333  }
   334  
   335  // GetPreBlockSeedCallBack
   336  void GetPreBlockSeedCallback(const FunctionCallbackInfo<Value> &info) {
   337    int err = NVM_SUCCESS;
   338    Isolate *isolate = info.GetIsolate();
   339    if (NULL == isolate) {
   340      LogFatalf("Unexpected error: failed to get isolate");
   341    }
   342    Local<Object> thisArg = info.Holder();
   343    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   344  
   345    if (info.Length() != 1) {
   346      isolate->ThrowException(String::NewFromUtf8(
   347          isolate, "Blockchain.GetPreBlockSeed() requires 1 arguments"));
   348      return;
   349    }
   350    
   351    Local<Value> offset = info[0];
   352    if (!offset->IsNumber()) {
   353      isolate->ThrowException(
   354          String::NewFromUtf8(isolate, "Blockchain.GetPreBlockSeed(), the argument must be a number")); 
   355      return;
   356    }
   357  
   358    double v = Number::Cast(*offset)->Value();
   359    if (v > ULLONG_MAX || v <= 0) {
   360      isolate->ThrowException(
   361          String::NewFromUtf8(isolate, "Blockchain.GetPreBlockSeed(), argument out of range"));
   362      return;
   363    }
   364  
   365   if (v != (double)(unsigned long long)v) {
   366      isolate->ThrowException(
   367          String::NewFromUtf8(isolate, "Blockchain.GetPreBlockSeed(), argument must be integer"));
   368      return;
   369    }
   370  
   371    size_t cnt = 0;
   372    char *result = NULL;
   373    char *exceptionInfo = NULL;
   374    err = sGetPreBlockSeed(handler->Value(), (unsigned long long)(v), &cnt, &result, &exceptionInfo);
   375  
   376    DEAL_ERROR_FROM_GOLANG(err);
   377  
   378    if (result != NULL) {
   379      free(result);
   380      result = NULL;
   381    }
   382  
   383    if (exceptionInfo != NULL) {
   384      free(exceptionInfo);
   385      exceptionInfo = NULL;
   386    }
   387  
   388    // record storage usage.
   389    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   390  }
   391  
   392  void GetContractSourceCallback(const FunctionCallbackInfo<Value> &info) {
   393    Isolate *isolate = info.GetIsolate();
   394    Local<Object> thisArg = info.Holder();
   395    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   396  
   397    if (info.Length() != 1) {
   398      isolate->ThrowException(String::NewFromUtf8(
   399          isolate, "Blockchain.GetContractSource() requires 1 arguments"));
   400      return;
   401    }
   402  
   403    Local<Value> address = info[0];
   404    if (!address->IsString()) {
   405      isolate->ThrowException(
   406          String::NewFromUtf8(isolate, "address must be string"));
   407      return;
   408    }
   409  
   410    size_t cnt = 0;
   411  
   412    char *value = sGetContractSource(handler->Value(),
   413                             *String::Utf8Value(address->ToString()), &cnt);
   414    if (value == NULL) {
   415      info.GetReturnValue().SetNull();  //TODO: throw err
   416    } else {
   417      info.GetReturnValue().Set(String::NewFromUtf8(isolate, value));
   418      free(value);
   419    }
   420  
   421    // record storage usage.
   422    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   423  }
   424  
   425  void RunInnerContractSourceCallBack(const FunctionCallbackInfo<Value> &info) {
   426    Isolate *isolate = info.GetIsolate();
   427    Local<Object> thisArg = info.Holder();
   428    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   429  
   430    if (info.Length() != 4) {
   431      char msg[128];
   432      snprintf(msg, 128, "Blockchain.RunInnerContractSourceCallBack() requires 4 arguments,args:%d", info.Length());
   433      isolate->ThrowException(String::NewFromUtf8(
   434          isolate, msg));
   435      return;
   436    }
   437  
   438    Local<Value> address = info[0];
   439    if (!address->IsString()) {
   440      isolate->ThrowException(
   441          String::NewFromUtf8(isolate, "address must be string"));
   442      return;
   443    }
   444    Local<Value> funcName = info[1];
   445    if (!address->IsString()) {
   446      isolate->ThrowException(
   447          String::NewFromUtf8(isolate, "func must be string"));
   448      return;
   449    }
   450    Local<Value> val = info[2];
   451    if (!val->IsString()) {
   452      isolate->ThrowException(
   453          String::NewFromUtf8(isolate, "val must be string"));
   454      return;
   455    }
   456    Local<Value> args = info[3];
   457    if (!args->IsString()) {
   458      isolate->ThrowException(
   459          String::NewFromUtf8(isolate, "args must be string"));
   460      return;
   461    }
   462  
   463    size_t cnt = 0;
   464    char *value = sRunInnerContract(handler->Value(),
   465                             *String::Utf8Value(address->ToString()), *String::Utf8Value(funcName->ToString()),
   466                             *String::Utf8Value(val->ToString()), *String::Utf8Value(args->ToString()),
   467                             &cnt);
   468    // Local<Object> rObj = v8::Object::New(isolate);
   469    if (value == NULL) {
   470      Local<Context> context = isolate->GetCurrentContext();
   471      V8Engine *e = GetV8EngineInstance(context);
   472      SetInnerContractErrFlag(e);
   473      TerminateExecution(e);
   474    } else {
   475      // Local<Boolean> flag = Boolean::New(isolate, true);
   476      // rObj->Set(v8::String::NewFromUtf8(isolate, "code"), flag);
   477      // Local<String> valueStr = v8::String::NewFromUtf8(isolate, value);
   478  
   479      // rObj->Set(v8::String::NewFromUtf8(isolate, "data"), valueStr);
   480      // info.GetReturnValue().Set(rObj);
   481  
   482      info.GetReturnValue().Set(String::NewFromUtf8(isolate, value));
   483  
   484      free(value);
   485    }
   486  
   487    // record storage usage.
   488    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   489  }
   490  
   491  // Get Latest Nebulas Rank Callback
   492  void GetLatestNebulasRankCallback(const FunctionCallbackInfo<Value> &info) {
   493    int err = NVM_SUCCESS;
   494  
   495    Isolate *isolate = info.GetIsolate();
   496    Local<Object> thisArg = info.Holder();
   497    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   498  
   499    if (info.Length() != 1) {
   500      isolate->ThrowException(String::NewFromUtf8(
   501          isolate, "Blockchain.getLatestNebulasRank() requires 1 argument"));
   502      return;
   503    }
   504  
   505    Local<Value> address = info[0];
   506    if (!address->IsString()) {
   507      isolate->ThrowException(
   508          String::NewFromUtf8(isolate, "address must be string"));
   509      return;
   510    }
   511  
   512    size_t cnt = 0;
   513    char* result = NULL;
   514    char* exceptionInfo = NULL;
   515    err = sGetLatestNR(handler->Value(), *String::Utf8Value(address->ToString()), &cnt, &result, &exceptionInfo);
   516  
   517    DEAL_ERROR_FROM_GOLANG(err);
   518  
   519    if (result != NULL) {
   520      free(result);
   521      result = NULL;
   522    }
   523  
   524    if (exceptionInfo != NULL) {
   525      free(exceptionInfo);
   526      exceptionInfo = NULL;
   527    }
   528  
   529    // record storage usage.
   530    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   531  }
   532  
   533  // Get Latest Nebulas Rank Summary Callback
   534  void GetLatestNebulasRankSummaryCallback(const FunctionCallbackInfo<Value> &info) {
   535    int err = NVM_SUCCESS;
   536  
   537    Isolate *isolate = info.GetIsolate();
   538    Local<Object> thisArg = info.Holder();
   539    Local<External> handler = Local<External>::Cast(thisArg->GetInternalField(0));
   540  
   541    if (info.Length() != 0) {
   542      isolate->ThrowException(String::NewFromUtf8(
   543          isolate, "Blockchain.getLatestNebulasRankSummary() needs not argument"));
   544      return;
   545    }
   546  
   547    size_t cnt = 0;
   548    char* result = NULL;
   549    char* exceptionInfo = NULL;
   550    err = sGetLatestNRSum(handler->Value(), &cnt, &result, &exceptionInfo);
   551  
   552    DEAL_ERROR_FROM_GOLANG(err);
   553  
   554    if (result != NULL) {
   555      free(result);
   556      result = NULL;
   557    }
   558  
   559    if (exceptionInfo != NULL) {
   560      free(exceptionInfo);
   561      exceptionInfo = NULL;
   562    }
   563  
   564    // record storage usage.
   565    IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
   566  }