Skip to content
This repository has been archived by the owner on Oct 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #12 from Zilliqa/gas
Browse files Browse the repository at this point in the history
Gas support
  • Loading branch information
vaivaswatha authored Oct 19, 2020
2 parents 53f423f + a39ab81 commit e5768d7
Show file tree
Hide file tree
Showing 192 changed files with 43,428 additions and 17,195 deletions.
57 changes: 56 additions & 1 deletion include/ScillaVM/JITD.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ struct ScillaParams {
};

// Each ScillaJIT object compiles an LLVM-IR module and provides access
// to the symbols inside it.
// to the symbols inside it. It is recommended use ScillaJIT_Safe,
// which hides many private methods in this class and makes it safer.
class ScillaJIT {
private:
// Use the Create method to build a ScillaJIT object.
Expand Down Expand Up @@ -132,12 +133,19 @@ class ScillaJIT {
ScillaCacheManager * = nullptr);
// Get address for @Symbol inside the compiled IR, ready to be used.
void *getAddressFor(const std::string &Symbol);

// Initialize gas-remaining field in the code and initialize libraries.
uint64_t *initGasAndLibs(uint64_t GasRem);
// Execute a message.
Json::Value execMsg(const std::string &Balance, uint64_t GasLimit,
Json::Value &Msg);
// Initialize the contract state to field initialization values in the source.
// This is to be called only during deployment of the contract. Never again.
Json::Value initState(uint64_t GasLimit);
// What's the gas remaining from previous execution (initState / execMsg).
// Useful if execution was interrupted due to an exception.
// Use with care if you don't want to end up with a stale value.
uint64_t getGasRem();

// Allocate and own the memory for code owned by this object.
void *sAlloc(size_t Size);
Expand All @@ -152,4 +160,51 @@ class ScillaJIT {
~ScillaJIT();
};

// Typical usage:
// ScillaJIT_Safe::init(); : One time ever
// 1. auto SJ = ScillaJIT_Safe::create(...);
// 2. (a) Deployment (b) Transition execution
// a. auto Output = ScillaJIT_Safe::initState(...);
// OR
// b. auto Output = ScillaJIT_Safe::execMsg(...);
// 3. If ScillaError exception, check remaining gas with getGasRem().
class ScillaJIT_Safe : private ScillaJIT {
public:
// One time initialization.
static void init() { ScillaJIT::init(); }
// JIT Compile LLVM-IR @FileName. ModuleID is derived from @FileName.
// Optionally, a cache manager can be provided.
static std::unique_ptr<ScillaJIT_Safe>
create(const ScillaParams &SPs, const std::string &FileName,
const Json::Value &ContrParams, ScillaCacheManager *SCM = nullptr) {
ScillaJIT *Ptr =
ScillaJIT::create(SPs, FileName, ContrParams, SCM).release();
return std::unique_ptr<ScillaJIT_Safe>(static_cast<ScillaJIT_Safe *>(Ptr));
}
// JIT Compile LLVM-IR in @IR, affixing @ModuleID to it.
// Optionally, a cache manager can be provided.
static std::unique_ptr<ScillaJIT_Safe>
create(const ScillaParams &SPs, const std::string &IR,
const std::string &ModuleID, const Json::Value &ContrParams,
ScillaCacheManager *SCM = nullptr) {
ScillaJIT *Ptr =
ScillaJIT::create(SPs, IR, ModuleID, ContrParams, SCM).release();
return std::unique_ptr<ScillaJIT_Safe>(static_cast<ScillaJIT_Safe *>(Ptr));
}
// Execute a message.
Json::Value execMsg(const std::string &Balance, uint64_t GasLimit,
Json::Value &Msg) {
return ScillaJIT::execMsg(Balance, GasLimit, Msg);
}
// Initialize the contract state to field initialization values in the source.
// This is to be called only during deployment of the contract. Never again.
Json::Value initState(uint64_t GasLimit) {
return ScillaJIT::initState(GasLimit);
}
// What's the gas remaining from previous execution (initState / execMsg).
// Useful if execution was interrupted due to an exception.
// Use with care if you don't want to end up with a stale value.
uint64_t getGasRem() { return ScillaJIT::getGasRem(); }
};

} // namespace ScillaVM
32 changes: 26 additions & 6 deletions libjitd/JITD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,7 @@ std::unique_ptr<ScillaJIT> ScillaJIT::create(const ScillaParams &SPs,
// Set execptr in the generated code to THIS
auto ExecPtr = THIS->getAddressFor("_execptr");
*reinterpret_cast<ScillaJIT **>(ExecPtr) = THIS;
// Call the library initialisation function
auto initLibs =
reinterpret_cast<void (*)()>(THIS->getAddressFor("_init_libs"));
initLibs();

// Initialize contract parameters.
THIS->initContrParams(ContrParams);

Expand Down Expand Up @@ -350,14 +347,34 @@ void ScillaJIT::initContrParams(const Json::Value &CP) {
}
}

uint64_t *ScillaJIT::initGasAndLibs(uint64_t GasLimit) {
// Set gas limit in the JIT'ed code module.
auto GasRemPtr = reinterpret_cast<uint64_t *>(getAddressFor("_gasrem"));
*GasRemPtr = GasLimit;

// Call the library initialisation function.
auto initLibs =
reinterpret_cast<void (*)()>(getAddressFor("_init_libs"));
initLibs();

return GasRemPtr;
}

Json::Value ScillaJIT::initState(uint64_t GasLimit) {

auto GasRemPtr = initGasAndLibs(GasLimit);

// Let's setup the TransitionState for this transition.
TS = std::make_unique<TransitionState>("0", "0", GasLimit);
TS = std::make_unique<TransitionState>("0", "0", GasRemPtr);
auto fIS = reinterpret_cast<void (*)(void)>(getAddressFor("_init_state"));
fIS();
return TS->finalize();
}

uint64_t ScillaJIT::getGasRem() {
return *reinterpret_cast<uint64_t *>(getAddressFor("_gasrem"));
}

void *ScillaJIT::getAddressFor(const std::string &Symbol) {

auto SA = Jitter->lookup(Symbol);
Expand Down Expand Up @@ -402,8 +419,11 @@ Json::Value ScillaJIT::execMsg(const std::string &Balance, uint64_t GasLimit,
!AmountJ.isString())
CREATE_ERROR("Invalid Message");

auto GasRemPtr = initGasAndLibs(GasLimit);

// Let's setup the TransitionState for this transition.
TS = std::make_unique<TransitionState>(Balance, AmountJ.asString(), GasLimit);
TS =
std::make_unique<TransitionState>(Balance, AmountJ.asString(), GasRemPtr);

// Amount and Sender need to be prepended to the parameter list.
Json::Value AmountParam;
Expand Down
40 changes: 36 additions & 4 deletions libsrtl/ScillaBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ std::vector<ScillaFunctionsMap> getAllScillaBuiltins(void) {
ScillaFunctionsMap m[] = {
{"_print_scilla_val", (void *) _print_scilla_val},
{"_salloc", (void *) _salloc},
{"_out_of_gas", (void *) _out_of_gas},
{"_add_Int32", (void *) _add_Int32},
{"_add_Int64", (void *) _add_Int64},
{"_add_Int128", (void *) _add_Int128},
Expand Down Expand Up @@ -68,6 +69,8 @@ std::vector<ScillaFunctionsMap> getAllScillaBuiltins(void) {
{"_contains", (void *) _contains},
{"_remove", (void *) _remove},
{"_size", (void *) _size},
{"_literal_cost", (void *) _literal_cost},
{"_mapsortcost", (void *) _mapsortcost},
};
// clang-format on

Expand Down Expand Up @@ -124,7 +127,7 @@ Json::Value TransitionState::finalize(void) {
Es = Json::arrayValue;

// 3. Fill in other fields.
OutJ["gas_remaining"] = std::to_string(GasRemaining);
OutJ["gas_remaining"] = std::to_string(*GasRemPtr);
OutJ["_accepted"] = Accepted ? "true" : "false";
OutJ["scilla_major_version"] = "0";

Expand Down Expand Up @@ -228,6 +231,8 @@ void _print_scilla_val(const ScillaTypes::Typ *T, void *V) {

void *_salloc(ScillaJIT *SJ, size_t size) { return SJ->sAlloc(size); }

void _out_of_gas() { CREATE_ERROR("Ran out of gas"); }

ScillaTypes::Int32 _add_Int32(ScillaTypes::Int32 Lhs, ScillaTypes::Int32 Rhs) {
return SafeInt32(&Lhs) + SafeInt32(&Rhs);
}
Expand Down Expand Up @@ -432,7 +437,7 @@ void *_to_nat(ScillaJIT *SJ, ScillaTypes::Uint32 UI) {
return MemPrev;
}

void _send(ScillaJIT *SJ, const ScillaTypes::Typ *T, void *V) {
void _send(ScillaJIT *SJ, const ScillaTypes::Typ *T, const void *V) {
auto J = ScillaValues::toJSON(T, V);
// J is a Scilla list of Messages. Form a JSON array instead.
// TODO: Consider having a Scilla List -> std::vector and calling
Expand Down Expand Up @@ -460,12 +465,39 @@ void _send(ScillaJIT *SJ, const ScillaTypes::Typ *T, void *V) {
}
}

void _event(ScillaJIT *SJ, const ScillaTypes::Typ *T, void *V) {
uint64_t _literal_cost (const ScillaTypes::Typ *T, const void *V) {
return ScillaValues::literalCost(T, V);
}

uint64_t _mapsortcost (const ScillaParams::MapValueT *M) {
uint64_t Cost = 0;

// First calculate cost for sub-maps (if any).
for (auto &Itr : *M) {
if (boost::has_type<std::string>(Itr.second)) {
break;
}
ASSERT(boost::has_type<ScillaParams::MapValueT>(Itr.second));
auto *SubM = &boost::any_cast<const ScillaParams::MapValueT &>(Itr.second);
Cost += _mapsortcost(SubM);
}

// Cost of sorting *this* map.
auto Len = M->size();
if (Len > 0) {
auto LogLen = static_cast<int>(log(static_cast<float>(Len)));
Cost += (Len * LogLen);
}

return Cost;
}

void _event(ScillaJIT *SJ, const ScillaTypes::Typ *T, const void *V) {
auto J = ScillaValues::toJSON(T, V);
SJ->TS->processEvent(J);
}

void _throw(ScillaJIT *SJ, const ScillaTypes::Typ *T, void *V) {
void _throw(ScillaJIT *SJ, const ScillaTypes::Typ *T, const void *V) {
(void)SJ;
auto J = ScillaValues::toJSON(T, V);
SCILLA_EXCEPTION("Exception thrown: " + J.toStyledString());
Expand Down
20 changes: 14 additions & 6 deletions libsrtl/ScillaBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ std::vector<ScillaFunctionsMap> getAllScillaBuiltins(void);
class TransitionState {
SafeUint128 Balance;
SafeUint128 InAmount;
uint64_t GasRemaining;
uint64_t *GasRemPtr;
bool Accepted;
// Contains the output messages of executing a transition.
Json::Value OutJ;
Expand All @@ -47,8 +47,8 @@ class TransitionState {

public:
TransitionState(std::string Balance_P, std::string InAmount_P,
uint64_t GasLimit_P)
: Balance(Balance_P), InAmount(InAmount_P), GasRemaining(GasLimit_P),
uint64_t *GasRemPtr_P)
: Balance(Balance_P), InAmount(InAmount_P), GasRemPtr(GasRemPtr_P),
Accepted(false), OutJ(Json::objectValue){};

void processSend(Json::Value &M);
Expand All @@ -72,6 +72,9 @@ void _print_scilla_val(const ScillaVM::ScillaTypes::Typ *T, void *V);
// Allocate memory for JIT code owned by @SJ
void *_salloc(ScillaVM::ScillaJIT *SJ, size_t size);

// Handler for out-of-gas during execution
void _out_of_gas();

// Fetch field @Name whose type is @T. For map accesses, FetchVal can be false,
// to indicate that the return value is a Scilla `Bool`, indicating found or
// not.
Expand Down Expand Up @@ -135,13 +138,13 @@ uint8_t *_eq_Uint256(ScillaVM::ScillaJIT *SJ,
void *_to_nat(ScillaVM::ScillaJIT *SJ, ScillaVM::ScillaTypes::Uint32 UI);

void _send(ScillaVM::ScillaJIT *SJ, const ScillaVM::ScillaTypes::Typ *T,
void *V);
const void *V);

void _event(ScillaVM::ScillaJIT *SJ, const ScillaVM::ScillaTypes::Typ *T,
void *V);
const void *V);

void _throw(ScillaVM::ScillaJIT *SJ, const ScillaVM::ScillaTypes::Typ *T,
void *V);
const void *V);

uint8_t *_eq_String(ScillaVM::ScillaJIT *SJ, ScillaVM::ScillaTypes::String Lhs,
ScillaVM::ScillaTypes::String Rhs);
Expand Down Expand Up @@ -178,7 +181,12 @@ void *_contains(ScillaVM::ScillaJIT *SJ, const ScillaVM::ScillaTypes::Typ *T,

void *_remove(ScillaVM::ScillaJIT *SJ, const ScillaVM::ScillaTypes::Typ *T,
const ScillaVM::ScillaParams::MapValueT *M, const void *K);

// Scilla builtin _size : The size of a map.
ScillaVM::ScillaTypes::Uint32 _size(const ScillaVM::ScillaParams::MapValueT *M);

uint64_t _literal_cost (const ScillaVM::ScillaTypes::Typ *T, const void *V);
uint64_t _mapsortcost (const ScillaVM::ScillaParams::MapValueT *M);

} // extern "C"
#pragma clang diagnostic pop
Loading

0 comments on commit e5768d7

Please sign in to comment.