Skip to content
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
2 changes: 1 addition & 1 deletion core/primitives/address/address_codec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ namespace fc::primitives::address {

OUTCOME_TRY(address, decode(buffer));
address.network = net;
return address;
return std::move(address);
}

std::vector<uint8_t> checksum(const Address &address) {
Expand Down
3 changes: 2 additions & 1 deletion core/vm/actor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ add_library(actor
actor.cpp
init_actor.cpp
cron_actor.cpp
cron_actor_error.cpp
invoker.cpp
)
target_link_libraries(actor
address
cid
exit_code
hamt
)
2 changes: 1 addition & 1 deletion core/vm/actor/actor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace fc::vm::actor {
ContentIdentifier code{common::kEmptyCid};
ContentIdentifier head{common::kEmptyCid};
uint64_t nonce{};
BigInt balance;
BigInt balance{};
};

bool operator==(const Actor &lhs, const Actor &rhs);
Expand Down
51 changes: 51 additions & 0 deletions core/vm/actor/actor_method.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef CPP_FILECOIN_CORE_VM_ACTOR_ACTOR_METHOD_HPP
#define CPP_FILECOIN_CORE_VM_ACTOR_ACTOR_METHOD_HPP

#include "codec/cbor/cbor.hpp"
#include "common/buffer.hpp"
#include "common/outcome.hpp"
#include "vm/actor/actor.hpp"
#include "vm/exit_code/exit_code.hpp"
#include "vm/vm_context.hpp"

namespace fc::vm::actor {
using common::Buffer;

/// Actor method signature
using ActorMethod = std::function<outcome::result<Buffer>(
const Actor &, VMContext &, gsl::span<const uint8_t>)>;

/// Actor methods exported by number
using ActorExports = std::map<uint64_t, ActorMethod>;

constexpr VMExitCode DECODE_ACTOR_PARAMS_ERROR{1};

/// Decode actor params, raises appropriate error
template <typename T>
outcome::result<T> decodeActorParams(gsl::span<const uint8_t> params_bytes) {
auto maybe_params = codec::cbor::decode<T>(params_bytes);
if (!maybe_params) {
return DECODE_ACTOR_PARAMS_ERROR;
}
return maybe_params;
}

constexpr VMExitCode ENCODE_ACTOR_PARAMS_ERROR{1};

/// Encode actor params, raises appropriate error
template <typename T>
outcome::result<std::vector<uint8_t>> encodeActorParams(const T &params) {
auto maybe_bytes = codec::cbor::encode(params);
if (!maybe_bytes) {
return ENCODE_ACTOR_PARAMS_ERROR;
}
return maybe_bytes;
}
} // namespace fc::vm::actor

#endif // CPP_FILECOIN_CORE_VM_ACTOR_ACTOR_METHOD_HPP
33 changes: 19 additions & 14 deletions core/vm/actor/cron_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@
*/

#include "vm/actor/cron_actor.hpp"
#include "vm/actor/cron_actor_error.hpp"

std::vector<fc::vm::actor::CronTableEntry> fc::vm::actor::CronActor::entries = {
{kStoragePowerAddress, SpaMethods::CHECK_PROOF_SUBMISSIONS}};
namespace fc::vm::actor {
std::vector<CronTableEntry> CronActor::entries = {
{kStoragePowerAddress, SpaMethods::CHECK_PROOF_SUBMISSIONS}};

fc::outcome::result<void> fc::vm::actor::CronActor::epochTick(
fc::vm::actor::Actor &actor,
fc::vm::VMContext &vmctx,
const std::vector<uint8_t> &params) {
if (!(vmctx.message().from == kCronAddress)) {
return CronActorError::WRONG_CALL;
}
outcome::result<Buffer> CronActor::epochTick(
const Actor &actor,
vm::VMContext &vmctx,
gsl::span<const uint8_t> params) {
if (!(vmctx.message().from == kCronAddress)) {
return WRONG_CALL;
}

for (const auto &entry : entries) {
OUTCOME_TRY(vmctx.send(entry.to_addr, entry.method_num, BigInt(0), {}));
for (const auto &entry : entries) {
OUTCOME_TRY(vmctx.send(entry.to_addr, entry.method_num, BigInt(0), {}));
}
return outcome::success();
}
return outcome::success();
}

ActorExports CronActor::exports = {
{2, ActorMethod(CronActor::epochTick)},
};
} // namespace fc::vm::actor
15 changes: 9 additions & 6 deletions core/vm/actor/cron_actor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@
#ifndef CPP_FILECOIN_CORE_VM_ACTOR_CRON_ACTOR_HPP
#define CPP_FILECOIN_CORE_VM_ACTOR_CRON_ACTOR_HPP

#include "vm/actor/actor.hpp"
#include "vm/actor/actor_method.hpp"
#include "vm/actor/storage_power_actor.hpp"
#include "vm/vm_context.hpp"

namespace fc::vm::actor {

struct CronTableEntry {
Address to_addr;
uint64_t method_num;
uint64_t method_num{};
};

struct CronActor {
static constexpr VMExitCode WRONG_CALL{1};

/**
* Entries is a set of actors (and corresponding methods) to call during
* EpochTick
Expand All @@ -31,9 +32,11 @@ namespace fc::vm::actor {
* @param params from Lotus(doesn't use)
* @return success or error
*/
static outcome::result<void> epochTick(Actor &actor,
vm::VMContext &vmctx,
const std::vector<uint8_t> &params);
static outcome::result<Buffer> epochTick(const Actor &actor,
VMContext &vmctx,
gsl::span<const uint8_t> params);

static ActorExports exports;
};

} // namespace fc::vm::actor
Expand Down
18 changes: 0 additions & 18 deletions core/vm/actor/cron_actor_error.cpp

This file was deleted.

26 changes: 0 additions & 26 deletions core/vm/actor/cron_actor_error.hpp

This file was deleted.

33 changes: 33 additions & 0 deletions core/vm/actor/invoker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "vm/actor/invoker.hpp"

#include "vm/actor/cron_actor.hpp"

namespace fc::vm::actor {
Invoker::Invoker() {
builtin_[actor::kCronCodeCid] = actor::CronActor::exports;
}

outcome::result<Buffer> Invoker::invoke(const Actor &actor,
VMContext &context,
uint64_t method,
gsl::span<const uint8_t> params) {
if (actor.code == actor::kAccountCodeCid) {
return CANT_INVOKE_ACCOUNT_ACTOR;
}
auto maybe_builtin_actor = builtin_.find(actor.code);
if (maybe_builtin_actor == builtin_.end()) {
return NO_CODE_OR_METHOD;
}
auto builtin_actor = maybe_builtin_actor->second;
auto maybe_builtin_method = builtin_actor.find(method);
if (maybe_builtin_method == builtin_actor.end()) {
return NO_CODE_OR_METHOD;
}
return maybe_builtin_method->second(actor, context, params);
}
} // namespace fc::vm::actor
29 changes: 29 additions & 0 deletions core/vm/actor/invoker.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef CPP_FILECOIN_CORE_VM_ACTOR_INVOKER_HPP
#define CPP_FILECOIN_CORE_VM_ACTOR_INVOKER_HPP

#include "vm/actor/actor_method.hpp"

namespace fc::vm::actor {
/// Finds and loads actor code, invokes actor methods
class Invoker {
public:
static constexpr VMExitCode CANT_INVOKE_ACCOUNT_ACTOR{254};
static constexpr VMExitCode NO_CODE_OR_METHOD{255};

Invoker();
outcome::result<Buffer> invoke(const Actor &actor,
VMContext &context,
uint64_t method,
gsl::span<const uint8_t> params);

private:
std::map<CID, ActorExports> builtin_;
};
} // namespace fc::vm::actor

#endif // CPP_FILECOIN_CORE_VM_ACTOR_INVOKER_HPP
1 change: 1 addition & 0 deletions core/vm/exit_code/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ add_library(exit_code
impl/exit_code.cpp
)
target_link_libraries(exit_code
outcome
)
15 changes: 15 additions & 0 deletions core/vm/exit_code/exit_code.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@

#include <string>

#include "common/outcome.hpp"

namespace fc::vm {
/**
* VM exit code enum for outcome errors. Meaning of exit codes may be
* different across actors.
*/
enum class VMExitCode : uint8_t {};

/// Distinguish VMExitCode errors from other errors
bool isVMExitCode(const std::error_code &error);
} // namespace fc::vm

OUTCOME_HPP_DECLARE_ERROR(fc::vm, VMExitCode);

namespace fc::vm::exit_code {

/**
Expand Down
10 changes: 10 additions & 0 deletions core/vm/exit_code/impl/exit_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

#include "common/enum.hpp"

OUTCOME_CPP_DEFINE_CATEGORY(fc::vm, VMExitCode, e) {
return "vm exit code";
}

namespace fc::vm {
bool isVMExitCode(const std::error_code &error) {
return error.category() == __libp2p::Category<VMExitCode>::get();
}
} // namespace fc::vm

using fc::common::to_int;
using fc::vm::exit_code::ErrorCode;
using fc::vm::exit_code::ExitCode;
Expand Down
7 changes: 7 additions & 0 deletions test/core/vm/actor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@ target_link_libraries(cron_actor_test
actor
hexutil
)

addtest(invoker_test
invoker_test.cpp
)
target_link_libraries(invoker_test
actor
)
3 changes: 1 addition & 2 deletions test/core/vm/actor/cron_actor_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <gtest/gtest.h>
#include "testutil/outcome.hpp"
#include "vm/actor/actor.hpp"
#include "vm/actor/cron_actor_error.hpp"
#include "vm_context_mock.hpp"

using namespace fc::vm;
Expand All @@ -25,7 +24,7 @@ TEST(CronActorTest, WrongSender) {
EXPECT_CALL(vmctx, message())
.WillRepeatedly(testing::Return(message_wrong_sender));
EXPECT_OUTCOME_FALSE(err, actor::CronActor::epochTick(actor, vmctx, {}));
ASSERT_EQ(err, actor::CronActorError::WRONG_CALL);
ASSERT_EQ(err, actor::CronActor::WRONG_CALL);
}

/**
Expand Down
47 changes: 47 additions & 0 deletions test/core/vm/actor/invoker_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "vm/actor/invoker.hpp"

#include <gtest/gtest.h>
#include "testutil/cbor.hpp"
#include "testutil/outcome.hpp"
#include "vm/actor/cron_actor.hpp"
#include "vm_context_mock.hpp"

using fc::vm::VMExitCode;

/// invoker returns error or invokes actor method
TEST(InvokerTest, InvokeCron) {
using namespace fc::vm::actor;

Invoker invoker;
fc::vm::MockVMContext vmc;

EXPECT_OUTCOME_ERROR(Invoker::CANT_INVOKE_ACCOUNT_ACTOR, invoker.invoke({kAccountCodeCid}, vmc, 0, {}));
EXPECT_OUTCOME_ERROR(Invoker::NO_CODE_OR_METHOD, invoker.invoke({kEmptyObjectCid}, vmc, 0, {}));
EXPECT_OUTCOME_ERROR(Invoker::NO_CODE_OR_METHOD, invoker.invoke({kCronCodeCid}, vmc, 1000, {}));

EXPECT_CALL(vmc, message())
.WillRepeatedly(testing::Return(fc::vm::Message{kInitAddress}));
EXPECT_OUTCOME_ERROR(CronActor::WRONG_CALL, invoker.invoke({kCronCodeCid}, vmc, 2, {}));
}

/// decodeActorParams returns error or decoded params
TEST(InvokerTest, DecodeActorParams) {
using fc::vm::actor::decodeActorParams;

// 80 is cbor empty list, not int
EXPECT_OUTCOME_ERROR(fc::vm::actor::DECODE_ACTOR_PARAMS_ERROR, decodeActorParams<int>("80"_unhex));
EXPECT_OUTCOME_EQ(decodeActorParams<int>("03"_unhex), 3);
}

/// encodeActorParams returns error or encoded params
TEST(InvokerTest, EncodeActorParams) {
using fc::vm::actor::encodeActorParams;

EXPECT_OUTCOME_ERROR(fc::vm::actor::ENCODE_ACTOR_PARAMS_ERROR, encodeActorParams(fc::common::kEmptyCid));
EXPECT_OUTCOME_EQ(encodeActorParams(3), "03"_unhex);
}
Loading