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

Commit

Permalink
Support for _lengthof Scilla operation (#40)
Browse files Browse the repository at this point in the history
* Add Iterate test. Doesn't work as _lengthof isn't there

* Add _lengthof op and fix/add simple-iterate test

* Some assertions and code formatting

* Fix unused variable used in ASSERT
  • Loading branch information
vaivaswatha authored Jun 30, 2021
1 parent 4708f95 commit 0b4d4e0
Show file tree
Hide file tree
Showing 13 changed files with 796 additions and 26 deletions.
53 changes: 28 additions & 25 deletions libScillaRTL/ScillaBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,31 +643,14 @@ void *_to_nat(ScillaExecImpl *SJ, SafeUint32 UI) {
}

void _send(ScillaExecImpl *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
// that before toJSON is called above.
auto *JJ = &J;
auto ErrMsg = "Invalid JSON constructed from send";
while (true) {
if (!JJ->isObject())
CREATE_ERROR(ErrMsg);
auto *JConstr = &(JJ->operator[]("constructor"));
if (!JConstr->isString())
CREATE_ERROR(ErrMsg);
auto CName = JConstr->asString();
if (CName == "Cons") {
auto *JArgs = &(JJ->operator[]("arguments"));
if (!JArgs->isArray() || JArgs->size() != 2)
CREATE_ERROR(ErrMsg);
SJ->TS->processSend(JArgs->operator[](0));
JJ = &(JArgs->operator[](1));
} else if (CName == "Nil") {
break;
} else {
CREATE_ERROR(ErrMsg);
}
}
ASSERT_MSG(T->m_t == ScillaTypes::Typ::ADT_typ &&
std::string(T->m_sub.m_spladt->m_parent->m_tName) == "List",
"_lengthof: List expected, got " + ScillaTypes::Typ::toString(T));
ScillaValues::iterScillaList(
T, V, [SJ](const ScillaTypes::Typ *ElmT, const void *ElmV) -> void {
auto J = ScillaValues::toJSON(ElmT, ElmV);
SJ->TS->processSend(J);
});
}

uint64_t _literal_cost(const ScillaTypes::Typ *T, const void *V) {
Expand Down Expand Up @@ -1182,4 +1165,24 @@ SafeUint32 _size(const ScillaParams::MapValueT *M) {
return SafeUint32(S32);
}

uint64_t _lengthof(const ScillaTypes::Typ *T, const void *V) {
switch (T->m_t) {
case ScillaTypes::Typ::Map_typ: {
auto *M = reinterpret_cast<const ScillaParams::MapValueT *>(V);
return M->size();
}
case ScillaTypes::Typ::ADT_typ: {
ASSERT_MSG(std::string(T->m_sub.m_spladt->m_parent->m_tName) == "List",
"_lengthof: List expected, got " +
(std::string(T->m_sub.m_spladt->m_parent->m_tName)));
uint64_t Len = 0;
ScillaValues::iterScillaList(
T, V, [&Len](const ScillaTypes::Typ *, const void *) { Len++; });
return Len;
}
default:
CREATE_ERROR("_lengthof: Invalid input value");
}
}

} // end of extern "C".
1 change: 1 addition & 0 deletions libScillaRTL/ScillaBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,5 +387,6 @@ ScillaRTL::SafeUint32 _size(const ScillaRTL::ScillaParams::MapValueT *M);

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

} // extern "C"
2 changes: 1 addition & 1 deletion libScillaRTL/ScillaExecImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ Json::Value ScillaExecImpl::execMsg(const std::string &Balance,
(TypeJ = P.get("type", Json::nullValue)) == Json::nullValue ||
(ValueJ = P.get("value", Json::nullValue)) == Json::nullValue ||
!VNameJ.isString() || !TypeJ.isString()) {
CREATE_ERROR("Incorrect paramter format in message JSON.");
CREATE_ERROR("Incorrect parameter format in message JSON.");
}
auto *T = parseTypeString(TypeJ.asString());
ParamTypes.push_back(T);
Expand Down
2 changes: 2 additions & 0 deletions libScillaRTL/ScillaTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const uint8_t Bool_True_Tag = 0;
const uint8_t Bool_False_Tag = 1;
const uint8_t Nat_Zero_Tag = 0;
const uint8_t Nat_Succ_Tag = 1;
const uint8_t List_Cons_Tag = 0;
const uint8_t List_Nil_Tag = 1;

struct PrimTyp {

Expand Down
34 changes: 34 additions & 0 deletions libScillaRTL/ScillaValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,5 +854,39 @@ uint64_t literalCost(const ScillaTypes::Typ *T, const void *V) {
CREATE_ERROR("Unreachable");
}

void iterScillaList(const ScillaTypes::Typ *T, const void *Val,
ScillaValueCallback F) {

using namespace ScillaTypes;
ASSERT(T->m_t == ScillaTypes::Typ::ADT_typ);
ADTTyp::Specl *Sp = T->m_sub.m_spladt;
ASSERT(std::string(Sp->m_parent->m_tName) == "List");
ASSERT(Sp->m_parent->m_numTArgs == 1);

const ScillaTypes::Typ *ElmT = Sp->m_TArgs[0];

const void *V = Val;
auto Tag = *reinterpret_cast<const uint8_t *>(V);
while (Tag == List_Cons_Tag) {
ASSERT(std::string(Sp->m_constrs[Tag]->m_cName) == "Cons" &&
Sp->m_constrs[Tag]->m_numArgs == 2 &&
Sp->m_constrs[Tag]->m_args[0] == ElmT &&
Sp->m_constrs[Tag]->m_args[1] == T);

auto VP = reinterpret_cast<const uint8_t *>(V);
// Increment VP once to go past the Tag.
VP++;
if (ScillaTypes::Typ::isBoxed(ElmT))
F(ElmT, *reinterpret_cast<const void *const *>(VP));
else
F(ElmT, reinterpret_cast<const void *>(VP));
// Go past this element to the next sublist.
VP += ScillaTypes::Typ::sizeOf(ElmT);
// Update the iterators.
V = *reinterpret_cast<const void *const *>(VP);
Tag = *reinterpret_cast<const uint8_t *>(V);
}
}

} // namespace ScillaValues
} // namespace ScillaRTL
10 changes: 10 additions & 0 deletions libScillaRTL/ScillaValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,15 @@ void serializeForHashing(ByteVec &Ret, const ScillaTypes::Typ *T,
// Compatible with literal_cost in Gas.ml in Scilla_base.
uint64_t literalCost(const ScillaTypes::Typ *T, const void *V);

// Iterate over a Scilla list, apply F to each element.
// F is passed the element type and the element.
// As usual:
// - for boxed values, the pointer passed is the boxing pointer.
// - for non-boxed values, their address is passed and must be loaded from.
using ScillaValueCallback =
std::function<void(const ScillaTypes::Typ *T, const void *)>;
void iterScillaList(const ScillaTypes::Typ *T, const void *V,
ScillaValueCallback F);

} // namespace ScillaValues
} // namespace ScillaRTL
19 changes: 19 additions & 0 deletions testsuite/ContrTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,25 @@ BOOST_AUTO_TEST_CASE(state_00_message_badinit_fail) {

BOOST_AUTO_TEST_SUITE_END() // simple_map

BOOST_AUTO_TEST_SUITE(simple_iterate)

ContractTest EventTests = {
"simple-iterate.ll",
{{"message_NEvents", "simple-iterate.message_NEvents.json",
"empty_init.json", "simple-iterate.contrinfo.json",
"simple-iterate.state.json", "simple-iterate.state.json",
"simple-iterate.output.json", "blockchain_default.json"}}};

BOOST_AUTO_TEST_CASE(unique_jits) {
testMessages(EventTests, false /* CommonJIT */);
}

BOOST_AUTO_TEST_CASE(common_jit) {
testMessages(EventTests, true /* CommonJIT */);
}

BOOST_AUTO_TEST_SUITE_END() // simple_iterate

BOOST_AUTO_TEST_SUITE(event)

ContractTest EventTests = {
Expand Down
62 changes: 62 additions & 0 deletions testsuite/contr/simple-iterate.contrinfo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"contract_info": {
"scilla_major_version": "0",
"vname": "SimpleIterate",
"params": [],
"fields": [],
"transitions": [
{
"vname": "NEvents",
"params": [ { "vname": "nlist", "type": "List (Int32)" } ]
}
],
"procedures": [
{ "vname": "EventN", "params": [ { "vname": "n", "type": "Int32" } ] }
],
"events": [
{ "vname": "FooN", "params": [ { "vname": "n", "type": "Int32" } ] }
],
"ADTs": [
{
"tname": "Option",
"tparams": [ "'A" ],
"tmap": [
{ "cname": "Some", "argtypes": [ "'A" ] },
{ "cname": "None", "argtypes": [] }
]
},
{
"tname": "Bool",
"tparams": [],
"tmap": [
{ "cname": "True", "argtypes": [] },
{ "cname": "False", "argtypes": [] }
]
},
{
"tname": "Nat",
"tparams": [],
"tmap": [
{ "cname": "Zero", "argtypes": [] },
{ "cname": "Succ", "argtypes": [ "Nat" ] }
]
},
{
"tname": "List",
"tparams": [ "'A" ],
"tmap": [
{ "cname": "Cons", "argtypes": [ "'A", "List ('A)" ] },
{ "cname": "Nil", "argtypes": [] }
]
},
{
"tname": "Pair",
"tparams": [ "'A", "'B" ],
"tmap": [ { "cname": "Pair", "argtypes": [ "'A", "'B" ] } ]
}
]
},
"warnings": [],
"gas_remaining": "9999"
}

Loading

0 comments on commit 0b4d4e0

Please sign in to comment.