Skip to content
This repository was archived by the owner on Oct 28, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 16 additions & 29 deletions libScillaRTL/ScillaBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@ void TransitionState::processMessage(std::string OutType, Json::Value &M) {
}

void TransitionState::processSend(Json::Value &M) {
processMessage("messages", M);
Json::Value AmtJ = M.get("_amount", Json::nullValue);
if (AmtJ.isString()) {
auto AmtV = SafeUint128(AmtJ.asString());
if (AmtV > Balance) {
CREATE_ERROR("Not enough balance to send _amount in message.\n" +
M.toStyledString());
}
Balance = Balance - AmtV;
processMessage("messages", M);
} else {
CREATE_ERROR("Invalid outgoing message. _amount not found.\n" +
M.toStyledString());
}
}

void TransitionState::processEvent(Json::Value &M) {
Expand All @@ -69,19 +81,9 @@ void TransitionState::processAccept(void) {
bool TransitionState::HasAccepted(void) const { return Accepted; }

Json::Value TransitionState::finalize(uint64_t GasRem) {
// 1. Process all outgoing "_amount"s and subtract from Balance.
// 1. If there are no ougoing messages, set an empty array.
Json::Value &Ms = OutJ["messages"];
if (Ms.isArray()) {
for (const Json::Value &M : Ms) {
auto Amount = M["_amount"];
ASSERT(Amount.isString());
SafeUint128 AmountSUI(Amount.asString());
if (AmountSUI > Balance) {
SCILLA_EXCEPTION("Not enough balance to send _amount in all messages");
}
Balance = Balance - AmountSUI;
}
} else {
if (!Ms.isArray()) {
Ms = Json::arrayValue;
}

Expand Down Expand Up @@ -238,20 +240,7 @@ void *fetchFieldHelper(ScillaExecImpl *SJ, const std::string &Addr,
} else {
auto Val = std::any_cast<std::string>(StringOrMapVal);
Json::Value ValJ = parseJSONString(Val);
auto Res = ScillaValues::fromJSON(SJ->OM, T, ValJ);
// If the query is for `_sender`'s `_balance`, and we've accepted
// money being sent in, then that must be subtracted and shown.
if (std::string(Name) == "_balance" && !Addr.empty() &&
Addr == SJ->TS->SenderAddr && SJ->TS->HasAccepted()) {
// Assert that the value we're returning is indeed Uint128.
ASSERT(T->m_t == ScillaTypes::Typ::Prim_typ &&
T->m_sub.m_primt->m_pt == ScillaTypes::PrimTyp::Uint_typ &&
T->m_sub.m_primt->m_detail.m_intBW ==
ScillaTypes::PrimTyp::Bits128);
auto *SenderBal = reinterpret_cast<SafeUint128 *>(Res);
*SenderBal = *SenderBal - SJ->TS->InAmount;
}
return Res;
return ScillaValues::fromJSON(SJ->OM, T, ValJ);
}
}

Expand Down Expand Up @@ -606,8 +595,6 @@ void *_fetch_field(ScillaExecImpl *SJ, const char *Name,
if (std::string(Name) == "_balance") {
// TODO: This is inefficient, It also allocates memory on every call.
// A better idea: https://github.com/Zilliqa/scilla-compiler/issues/73.
// On the other hand, due to https://github.com/Zilliqa/scilla/issues/1007,
// we may want to get rid of this special handling altogether.
return SJ->OM.create<SafeUint128>(SJ->TS->getCurBal());
}
return fetchFieldHelper(SJ, std::string(), Name, T, NumIdx, Indices,
Expand Down
79 changes: 71 additions & 8 deletions testsuite/ContrTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct ContractTest {
};

// Give a file foo.ll, return foo.dbg.ll.
std::string deriveDbgFilename(std::string Filename) {
std::string deriveDbgFilename(const std::string &Filename) {
auto BaseName = boost::filesystem::basename(Filename);
auto Extension = boost::filesystem::extension(Filename);
return BaseName + ".dbg" + Extension;
Expand Down Expand Up @@ -181,7 +181,7 @@ void testMessages(const ContractTest &CT, bool CommonJIT) {
testMessagesHelper(CT, CommonJIT);
BOOST_TEST_CHECKPOINT("Testing " + CT.ContrFilename + " with debug LLVM-IR");
auto CTDbg(CT);
deriveDbgFilename(CTDbg.ContrFilename);
CTDbg.ContrFilename = deriveDbgFilename(CTDbg.ContrFilename);
testMessagesHelper(CTDbg, CommonJIT);
}

Expand Down Expand Up @@ -796,7 +796,7 @@ BOOST_AUTO_TEST_CASE(common_jit) {

auto prepareRemoteStateReadsSuccTests = []() {
ContractTest RSRSTs{"remote_state_reads.ll", {}};
for (int I = 1; I <= 11; I++) {
for (int I = 1; I <= 10; I++) {
ContractTest::Input ThisInput = {
"remote_state_reads_succ_" + std::to_string(I),
"remote_state_reads.message_" + std::to_string(I) + ".json",
Expand Down Expand Up @@ -845,11 +845,7 @@ BOOST_AUTO_TEST_CASE(succ_common_jit_2) {
}

BOOST_AUTO_TEST_CASE(fail_msgs) {
for (int I = 101; I <= 131; I++) {
if (I == 127) {
// https://github.com/Zilliqa/scilla-rtl/issues/46
continue;
}
for (int I = 101; I <= 130; I++) {
BOOST_TEST_CHECKPOINT("Executing remote_state_reads_fail_" << I);
testMessageFail("remote_state_reads.ll",
"remote_state_reads.message_" + std::to_string(I) + ".json",
Expand Down Expand Up @@ -941,4 +937,71 @@ BOOST_AUTO_TEST_CASE(succ_common_jit) {

BOOST_AUTO_TEST_SUITE_END() // type_casts

BOOST_AUTO_TEST_SUITE(accounting_tests)

auto prepareAccountingSuccTests = []() {
ContractTest RSRSTs{"accounting_tests.ll", {}};
for (int I = 1; I <= 21; I++) {
ContractTest::Input ThisInput = {
"accounting_tests_succ_" + std::to_string(I),
"accounting_tests.message_" + std::to_string(I) + ".json",
"accounting_tests.init.json",
"accounting_tests.contrinfo.json",
"accounting_tests.state_" + std::to_string(I) + ".json",
"accounting_tests.ostate_" + std::to_string(I) + ".json",
"accounting_tests.output_" + std::to_string(I) + ".json",
"blockchain_default.json"};
RSRSTs.Inputs.push_back(ThisInput);
}
return RSRSTs;
};

BOOST_AUTO_TEST_CASE(succ_unique_jits) {
testMessages(prepareAccountingSuccTests(), false /* CommonJIT */);
}

BOOST_AUTO_TEST_CASE(succ_common_jit) {
testMessages(prepareAccountingSuccTests(), true /* CommonJIT */);
}

BOOST_AUTO_TEST_CASE(expfail) {
for (int I = 100; I <= 109; I++) {
BOOST_TEST_CHECKPOINT("Executing accounting_tests_fail_" << I);
testMessageFail("accounting_tests.ll",
"accounting_tests.message_" + std::to_string(I) + ".json",
"accounting_tests.init.json",
"accounting_tests.contrinfo.json",
"accounting_tests.state_" + std::to_string(I) + ".json",
"accounting_tests.output_" + std::to_string(I) + ".json",
"blockchain_default.json");
}
}

auto prepareAccountingSupportSuccTests = []() {
ContractTest RSRSTs{"accounting_tests_support.ll", {}};
for (int I = 1; I <= 6; I++) {
ContractTest::Input ThisInput = {
"accounting_tests_support_succ_" + std::to_string(I),
"accounting_tests_support.message_" + std::to_string(I) + ".json",
"empty_init.json",
"accounting_tests_support.contrinfo.json",
"accounting_tests_support.state_" + std::to_string(I) + ".json",
"accounting_tests_support.ostate_" + std::to_string(I) + ".json",
"accounting_tests_support.output_" + std::to_string(I) + ".json",
"blockchain_default.json"};
RSRSTs.Inputs.push_back(ThisInput);
}
return RSRSTs;
};

BOOST_AUTO_TEST_CASE(support_succ_unique_jits) {
testMessages(prepareAccountingSupportSuccTests(), false /* CommonJIT */);
}

BOOST_AUTO_TEST_CASE(support_succ_common_jit) {
testMessages(prepareAccountingSupportSuccTests(), true /* CommonJIT */);
}

BOOST_AUTO_TEST_SUITE_END() // accounting_tests

BOOST_AUTO_TEST_SUITE_END() // contr_exec
8 changes: 7 additions & 1 deletion testsuite/contr/accept.output_Accept3_fail.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
Not enough balance to send _amount in all messages
Not enough balance to send _amount in message.
{
"_amount" : "100",
"_recipient" : "0x1234567890123456789012345678901234567890",
"_tag" : "",
"params" : []
}
167 changes: 167 additions & 0 deletions testsuite/contr/accounting_tests.contrinfo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
{
"contract_info": {
"scilla_major_version": "0",
"vname": "AccountingTests",
"params": [
{
"vname": "support_contract",
"type":
"ByStr20 with contract field stored_strings : List (String) end"
}
],
"fields": [
{ "vname": "test_string_1", "type": "String", "depth": 0 },
{ "vname": "test_string_2", "type": "String", "depth": 0 },
{ "vname": "outgoing_amount", "type": "Uint128", "depth": 0 },
{ "vname": "max_outgoing_msgs", "type": "Uint128", "depth": 0 }
],
"transitions": [
{ "vname": "Reset", "params": [] },
{ "vname": "Test_Insufficient_Balance", "params": [] },
{ "vname": "Test_Send_1", "params": [] },
{ "vname": "Finalize_Test_Send_1", "params": [] },
{ "vname": "Test_Send_2", "params": [] },
{ "vname": "Finalize_Test_Send_2", "params": [] },
{ "vname": "Test_Send_3", "params": [] },
{ "vname": "Test_Send_3_Helper", "params": [] },
{ "vname": "Finalize_Test_Send_3", "params": [] },
{
"vname": "CheckSenderBalance",
"params": [ { "vname": "expected_balance", "type": "Uint128" } ]
},
{
"vname": "CheckRecipientBalance",
"params": [ { "vname": "expected_balance", "type": "Uint128" } ]
},
{ "vname": "Test_Send_4", "params": [] },
{ "vname": "Test_Send_5", "params": [] },
{ "vname": "Test_Send_6", "params": [] },
{ "vname": "Test_Send_7", "params": [] },
{ "vname": "Test_Send_8", "params": [] },
{ "vname": "Test_Send_9", "params": [] },
{ "vname": "Test_Send_10", "params": [] },
{ "vname": "Test_Send_11", "params": [] },
{ "vname": "Test_Send_12", "params": [] },
{ "vname": "Test_Send_13", "params": [] },
{ "vname": "Test_Send_14", "params": [] }
],
"procedures": [
{ "vname": "AssertReset", "params": [] },
{
"vname": "Finalize_Test_Send_Helper_2_Msgs",
"params": [ { "vname": "test_no", "type": "Uint128" } ]
},
{
"vname": "CheckBalance",
"params": [ { "vname": "expected_balance", "type": "Uint128" } ]
},
{
"vname": "CheckSupportBalance",
"params": [ { "vname": "expected_balance", "type": "Uint128" } ]
}
],
"events": [],
"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": [
{
"warning_message":
"Read only field, consider making it a contract parameter: test_string_2",
"start_location": {
"file":
"../../scilla-compiler//tests/codegen/contr/accounting_tests.scilla",
"line": 83,
"column": 9
},
"end_location": { "file": "", "line": 0, "column": 0 },
"warning_id": 3
},
{
"warning_message":
"Read only field, consider making it a contract parameter: test_string_1",
"start_location": {
"file":
"../../scilla-compiler//tests/codegen/contr/accounting_tests.scilla",
"line": 76,
"column": 9
},
"end_location": { "file": "", "line": 0, "column": 0 },
"warning_id": 3
},
{
"warning_message":
"Read only field, consider making it a contract parameter: outgoing_amount",
"start_location": {
"file":
"../../scilla-compiler//tests/codegen/contr/accounting_tests.scilla",
"line": 45,
"column": 13
},
"end_location": { "file": "", "line": 0, "column": 0 },
"warning_id": 3
},
{
"warning_message":
"Read only field, consider making it a contract parameter: max_outgoing_msgs",
"start_location": {
"file":
"../../scilla-compiler//tests/codegen/contr/accounting_tests.scilla",
"line": 46,
"column": 15
},
"end_location": { "file": "", "line": 0, "column": 0 },
"warning_id": 3
},
{
"warning_message": "Unused load statement to: s1",
"start_location": {
"file":
"../../scilla-compiler//tests/codegen/contr/accounting_tests.scilla",
"line": 152,
"column": 3
},
"end_location": { "file": "", "line": 0, "column": 0 },
"warning_id": 3
}
],
"gas_remaining": "9916"
}

Loading