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 }