Skip to content

Commit 060bfeb

Browse files
authored
Account actor (#71)
Signed-off-by: turuslan <[email protected]>
1 parent d9689e7 commit 060bfeb

File tree

9 files changed

+206
-20
lines changed

9 files changed

+206
-20
lines changed

core/vm/actor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#
55

66
add_library(actor
7+
account_actor.cpp
78
actor.cpp
89
init_actor.cpp
910
cron_actor.cpp

core/vm/actor/account_actor.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "vm/actor/account_actor.hpp"
7+
8+
namespace fc::vm::actor {
9+
outcome::result<Actor> AccountActor::create(
10+
const std::shared_ptr<StateTree> &state_tree, const Address &address) {
11+
if (!address.isKeyType()) {
12+
return CREATE_WRONG_ADDRESS_TYPE;
13+
}
14+
Actor actor{kAccountCodeCid, ActorSubstateCID{kEmptyObjectCid}, 0, 0};
15+
if (address.getProtocol() == Protocol::BLS) {
16+
OUTCOME_TRY(state,
17+
state_tree->getStore()->setCbor(AccountActorState{address}));
18+
actor.head = ActorSubstateCID{state};
19+
}
20+
OUTCOME_TRY(state_tree->registerNewAddress(address, actor));
21+
return actor;
22+
}
23+
24+
outcome::result<Address> AccountActor::resolveToKeyAddress(
25+
const std::shared_ptr<StateTree> &state_tree, const Address &address) {
26+
if (address.isKeyType()) {
27+
return address;
28+
}
29+
auto maybe_actor = state_tree->get(address);
30+
if (!maybe_actor) {
31+
return RESOLVE_NOT_FOUND;
32+
}
33+
auto actor = maybe_actor.value();
34+
if (actor.code != kAccountCodeCid) {
35+
return RESOLVE_NOT_ACCOUNT_ACTOR;
36+
}
37+
OUTCOME_TRY(account_actor_state,
38+
state_tree->getStore()->getCbor<AccountActorState>(actor.head));
39+
return account_actor_state.address;
40+
}
41+
} // namespace fc::vm::actor

core/vm/actor/account_actor.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef CPP_FILECOIN_CORE_VM_ACTOR_ACCOUNT_ACTOR_HPP
7+
#define CPP_FILECOIN_CORE_VM_ACTOR_ACCOUNT_ACTOR_HPP
8+
9+
#include "primitives/address/address_codec.hpp"
10+
#include "vm/exit_code/exit_code.hpp"
11+
#include "vm/state/state_tree.hpp"
12+
13+
namespace fc::vm::actor {
14+
using primitives::address::Address;
15+
using primitives::address::Protocol;
16+
using state::StateTree;
17+
18+
struct AccountActorState {
19+
Address address;
20+
};
21+
22+
template <class Stream,
23+
typename = std::enable_if_t<
24+
std::remove_reference_t<Stream>::is_cbor_encoder_stream>>
25+
Stream &operator<<(Stream &&s, const AccountActorState &state) {
26+
return s << (s.list() << state.address);
27+
}
28+
29+
template <class Stream,
30+
typename = std::enable_if_t<
31+
std::remove_reference_t<Stream>::is_cbor_decoder_stream>>
32+
Stream &operator>>(Stream &&s, AccountActorState &state) {
33+
s.list() >> state.address;
34+
return s;
35+
}
36+
37+
/// Account actors represent actors without code
38+
struct AccountActor {
39+
static constexpr VMExitCode CREATE_WRONG_ADDRESS_TYPE{1};
40+
static constexpr VMExitCode RESOLVE_NOT_FOUND{1};
41+
static constexpr VMExitCode RESOLVE_NOT_ACCOUNT_ACTOR{1};
42+
43+
/// Create account actor from BLS or Secp256k1 address
44+
static outcome::result<Actor> create(
45+
const std::shared_ptr<StateTree> &state_tree, const Address &address);
46+
/**
47+
* Get BLS address of account actor from ID address
48+
* @param state_tree state tree
49+
* @param address id address to be resolved to key address
50+
* @returns key address associated with id address
51+
*/
52+
static outcome::result<Address> resolveToKeyAddress(
53+
const std::shared_ptr<StateTree> &state_tree, const Address &address);
54+
};
55+
} // namespace fc::vm::actor
56+
57+
#endif // CPP_FILECOIN_CORE_VM_ACTOR_ACCOUNT_ACTOR_HPP

core/vm/state/state_tree.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,8 @@ namespace fc::vm::state {
6767
hamt_ = snapshot_;
6868
return outcome::success();
6969
}
70+
71+
std::shared_ptr<IpfsDatastore> StateTree::getStore() {
72+
return store_;
73+
}
7074
} // namespace fc::vm::state

core/vm/state/state_tree.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ namespace fc::vm::state {
1919
class StateTree {
2020
public:
2121
explicit StateTree(const std::shared_ptr<IpfsDatastore> &store);
22-
StateTree(const std::shared_ptr<IpfsDatastore> &store,
23-
const CID &root);
22+
StateTree(const std::shared_ptr<IpfsDatastore> &store, const CID &root);
2423
/// Set actor state, does not write to storage
2524
outcome::result<void> set(const Address &address, const Actor &actor);
2625
/// Get actor state
@@ -34,6 +33,8 @@ namespace fc::vm::state {
3433
outcome::result<CID> flush();
3534
/// Revert changes to last flushed state
3635
outcome::result<void> revert();
36+
/// Get store
37+
std::shared_ptr<IpfsDatastore> getStore();
3738

3839
private:
3940
std::shared_ptr<IpfsDatastore> store_;

test/core/vm/actor/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,12 @@ addtest(invoker_test
3434
target_link_libraries(invoker_test
3535
actor
3636
)
37+
38+
addtest(account_actor_test
39+
account_actor_test.cpp
40+
)
41+
target_link_libraries(account_actor_test
42+
actor
43+
state_tree
44+
ipfs_datastore_in_memory
45+
)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "vm/actor/account_actor.hpp"
7+
8+
#include "testutil/init_actor.hpp"
9+
10+
using fc::primitives::address::Address;
11+
using fc::vm::actor::AccountActor;
12+
using fc::vm::actor::AccountActorState;
13+
using fc::vm::state::StateTree;
14+
15+
/// Account actor state CBOR encoding and decoding
16+
TEST(AccountActorTest, AccountActorStateCbor) {
17+
AccountActorState state{Address::makeFromId(3)};
18+
expectEncodeAndReencode(state, "81420003"_unhex);
19+
}
20+
21+
/**
22+
* @given Empty state tree and actor
23+
* @when Create account actor with BLS address @and resolve BLS address from
24+
* assigned ID address
25+
* @then Returned BLS address is equal to original
26+
*/
27+
TEST(InitActorTest, CreateResolve) {
28+
auto state_tree = setupInitActor(nullptr);
29+
auto addr1 = Address::makeFromId(3);
30+
Address addr2{
31+
fc::primitives::address::Network::TESTNET,
32+
fc::primitives::address::BLSPublicKeyHash{
33+
"010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"_blob48}};
34+
fc::vm::actor::Actor actor{
35+
fc::vm::actor::kCronCodeCid,
36+
fc::vm::actor::ActorSubstateCID{"010001020002"_cid},
37+
0,
38+
0};
39+
40+
EXPECT_OUTCOME_ERROR(AccountActor::CREATE_WRONG_ADDRESS_TYPE,
41+
AccountActor::create(state_tree, addr1));
42+
43+
EXPECT_OUTCOME_ERROR(AccountActor::RESOLVE_NOT_FOUND,
44+
AccountActor::resolveToKeyAddress(state_tree, addr1));
45+
EXPECT_OUTCOME_TRUE_1(state_tree->set(addr1, actor));
46+
EXPECT_OUTCOME_ERROR(AccountActor::RESOLVE_NOT_ACCOUNT_ACTOR,
47+
AccountActor::resolveToKeyAddress(state_tree, addr1));
48+
49+
actor.code = fc::vm::actor::kAccountCodeCid;
50+
EXPECT_OUTCOME_TRUE(actor2, AccountActor::create(state_tree, addr2));
51+
EXPECT_EQ(actor2.code, fc::vm::actor::kAccountCodeCid);
52+
EXPECT_OUTCOME_TRUE(addr2_id, state_tree->lookupId(addr2));
53+
EXPECT_OUTCOME_EQ(AccountActor::resolveToKeyAddress(state_tree, addr2_id),
54+
addr2);
55+
}

test/core/vm/state/state_tree_test.cpp

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77

88
#include <gtest/gtest.h>
99
#include "primitives/address/address_codec.hpp"
10-
#include "storage/hamt/hamt.hpp"
11-
#include "storage/ipfs/impl/in_memory_datastore.hpp"
12-
#include "testutil/cbor.hpp"
13-
#include "vm/actor/init_actor.hpp"
10+
#include "testutil/init_actor.hpp"
1411

1512
using fc::primitives::BigInt;
1613
using fc::primitives::address::Address;
@@ -74,20 +71,11 @@ TEST_F(StateTreeTest, SetRevert) {
7471
* @then Actor state in the tree is same
7572
*/
7673
TEST_F(StateTreeTest, RegisterNewAddressLookupId) {
77-
using fc::vm::actor::InitActorState;
78-
using fc::vm::actor::kInitAddress;
79-
EXPECT_OUTCOME_TRUE(empty_map, Hamt(store_).flush());
80-
InitActorState init_actor_state{empty_map, 13};
81-
EXPECT_OUTCOME_TRUE(init_actor_state_cid, store_->setCbor(init_actor_state));
82-
Actor init_actor{CodeId{"010001020000"_cid},
83-
ActorSubstateCID{init_actor_state_cid},
84-
{},
85-
{}};
86-
EXPECT_OUTCOME_TRUE_1(tree_.set(kInitAddress, init_actor));
74+
auto tree = setupInitActor(nullptr, 13);
8775
Address address{fc::primitives::address::TESTNET,
8876
fc::primitives::address::ActorExecHash{}};
89-
EXPECT_OUTCOME_EQ(tree_.registerNewAddress(address, kActor), kAddressId);
90-
EXPECT_OUTCOME_EQ(tree_.lookupId(address), kAddressId);
91-
EXPECT_OUTCOME_EQ(tree_.get(address), kActor);
92-
EXPECT_OUTCOME_EQ(tree_.get(kAddressId), kActor);
77+
EXPECT_OUTCOME_EQ(tree->registerNewAddress(address, kActor), kAddressId);
78+
EXPECT_OUTCOME_EQ(tree->lookupId(address), kAddressId);
79+
EXPECT_OUTCOME_EQ(tree->get(address), kActor);
80+
EXPECT_OUTCOME_EQ(tree->get(kAddressId), kActor);
9381
}

test/testutil/init_actor.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef CPP_FILECOIN_TEST_TESTUTIL_INIT_ACTOR_HPP
2+
#define CPP_FILECOIN_TEST_TESTUTIL_INIT_ACTOR_HPP
3+
4+
#include <gtest/gtest.h>
5+
#include "storage/ipfs/impl/in_memory_datastore.hpp"
6+
#include "testutil/cbor.hpp"
7+
#include "vm/actor/init_actor.hpp"
8+
#include "vm/state/state_tree.hpp"
9+
10+
/// Sets up init actor state
11+
std::shared_ptr<fc::vm::state::StateTree> setupInitActor(
12+
std::shared_ptr<fc::vm::state::StateTree> state_tree,
13+
uint64_t next_id = 100) {
14+
if (!state_tree) {
15+
state_tree = std::make_shared<fc::vm::state::StateTree>(
16+
std::make_shared<fc::storage::ipfs::InMemoryDatastore>());
17+
}
18+
auto store = state_tree->getStore();
19+
EXPECT_OUTCOME_TRUE(empty_map, fc::storage::hamt::Hamt(store).flush());
20+
EXPECT_OUTCOME_TRUE(
21+
state, store->setCbor(fc::vm::actor::InitActorState{empty_map, next_id}));
22+
EXPECT_OUTCOME_TRUE_1(state_tree->set(fc::vm::actor::kInitAddress,
23+
{fc::vm::actor::kInitCodeCid,
24+
fc::vm::actor::ActorSubstateCID{state},
25+
0,
26+
0}));
27+
return state_tree;
28+
}
29+
30+
#endif // CPP_FILECOIN_TEST_TESTUTIL_INIT_ACTOR_HPP

0 commit comments

Comments
 (0)