Skip to content

Commit 647a822

Browse files
cpython vm for privileged accounts
1 parent 23b4ce8 commit 647a822

File tree

13 files changed

+282
-131
lines changed

13 files changed

+282
-131
lines changed

libraries/chain/eosio_contract.cpp

Lines changed: 4 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -159,20 +159,11 @@ void apply_eosio_setcode(apply_context& context) {
159159

160160
jit_account_deactivate(act.account.value);
161161

162-
if (act.vmtype == 1) {
163-
apply_eosio_setcode_py(context);
164-
return;
165-
} else if (act.vmtype == 2) {
166-
apply_eosio_setcode_evm(context);
167-
return;
168-
} else if (act.vmtype == 3) {
169-
apply_eosio_setcode_rpc(context);
170-
return;
171-
}
172162
context.require_authorization(act.account);
173163

174-
FC_ASSERT( act.vmtype == 0 );
164+
// FC_ASSERT( act.vmtype == 0 );
175165
FC_ASSERT( act.vmversion == 0 );
166+
FC_ASSERT(act.code.size() > 0);
176167

177168
fc::sha256 code_id; /// default ID == 0
178169

@@ -196,9 +187,7 @@ void apply_eosio_setcode(apply_context& context) {
196187
a.last_code_update = context.control.pending_block_time();
197188
a.code_version = code_id;
198189
a.code.resize( code_size );
199-
if( code_size > 0 )
200-
memcpy( a.code.data(), act.code.data(), code_size );
201-
190+
memcpy( a.code.data(), act.code.data(), code_size );
202191
});
203192

204193
const auto& account_sequence = db.get<account_sequence_object, by_name>(act.account);
@@ -209,55 +198,9 @@ void apply_eosio_setcode(apply_context& context) {
209198
if (new_size != old_size) {
210199
context.trx_context.add_ram_usage( act.account, new_size - old_size );
211200
}
212-
vm_manager::get().setcode(0, act.account);
201+
vm_manager::get().setcode(act.vmtype, act.account);
213202
}
214203

215-
void apply_eosio_setcode_py(apply_context& context) {
216-
auto& db = context.db;
217-
auto act = context.act.data_as<setcode>();
218-
context.require_authorization(act.account);
219-
220-
FC_ASSERT( act.vmtype == 1 );
221-
FC_ASSERT( act.vmversion == 0 );
222-
223-
auto code_id = fc::sha256::hash( act.code.data(), (uint32_t)act.code.size() );
224-
225-
if (act.code.size() > 5*1024) {
226-
elog("++++act.code.size() ${n}", ("n", act.code.size()));
227-
throw FC_EXCEPTION( fc::exception, "code size must be <= 5KB, actual code size is ${n}", ("n", act.code.size()));
228-
}
229-
230-
const auto& account = db.get<account_object,by_name>(act.account);
231-
232-
int64_t code_size = (int64_t)act.code.size();
233-
int64_t old_size = (int64_t)account.code.size() * config::setcode_ram_bytes_multiplier;
234-
int64_t new_size = code_size * config::setcode_ram_bytes_multiplier;
235-
236-
FC_ASSERT( account.code_version != code_id, "contract is already running this version of code" );
237-
// wlog( "set code: ${size}", ("size",act.code.size()));
238-
db.modify( account, [&]( auto& a ) {
239-
/** TODO: consider whether a microsecond level local timestamp is sufficient to detect code version changes*/
240-
#warning TODO: update setcode message to include the hash, then validate it in validate
241-
a.vm_type = act.vmtype;
242-
a.last_code_update = context.control.pending_block_time();
243-
a.code_version = code_id;
244-
a.code.resize( code_size );
245-
if( code_size > 0 )
246-
memcpy( a.code.data(), act.code.data(), code_size );
247-
248-
});
249-
250-
const auto& account_sequence = db.get<account_sequence_object, by_name>(act.account);
251-
db.modify( account_sequence, [&]( auto& aso ) {
252-
aso.code_sequence += 1;
253-
});
254-
255-
if (new_size != old_size) {
256-
context.trx_context.add_ram_usage( act.account, new_size - old_size );
257-
}
258-
vm_manager::get().setcode(1, act.account);
259-
// micropython_interface::get().on_setcode(act.account, act.code);
260-
}
261204

262205
void apply_eosio_setcode_evm(apply_context& context) {
263206
auto& db = context.db;
@@ -309,49 +252,6 @@ void apply_eosio_setcode_evm(apply_context& context) {
309252
}
310253
}
311254

312-
void apply_eosio_setcode_rpc(apply_context& context) {
313-
auto& db = context.db;
314-
auto act = context.act.data_as<setcode>();
315-
context.require_authorization(act.account);
316-
317-
FC_ASSERT( act.vmtype == 3);
318-
FC_ASSERT( act.vmversion == 0 );
319-
320-
auto code_id = fc::sha256::hash( act.code.data(), (uint32_t)act.code.size() );
321-
322-
const auto& account = db.get<account_object,by_name>(act.account);
323-
324-
325-
int64_t code_size = (int64_t)act.code.size();
326-
int64_t old_size = (int64_t)account.code.size() * config::setcode_ram_bytes_multiplier;
327-
int64_t new_size = code_size * config::setcode_ram_bytes_multiplier;
328-
329-
FC_ASSERT( account.code_version != code_id, "contract is already running this version of code" );
330-
// wlog( "set code: ${size}", ("size",act.code.size()));
331-
db.modify( account, [&]( auto& a ) {
332-
/** TODO: consider whether a microsecond level local timestamp is sufficient to detect code version changes*/
333-
#warning TODO: update setcode message to include the hash, then validate it in validate
334-
a.vm_type = act.vmtype;
335-
a.last_code_update = context.control.pending_block_time();
336-
a.code_version = code_id;
337-
a.code.resize( code_size );
338-
a.last_code_update = context.control.pending_block_time();
339-
memcpy( a.code.data(), act.code.data(), code_size );
340-
341-
});
342-
343-
const auto& account_sequence = db.get<account_sequence_object, by_name>(act.account);
344-
db.modify( account_sequence, [&]( auto& aso ) {
345-
aso.code_sequence += 1;
346-
});
347-
348-
if (new_size != old_size) {
349-
context.trx_context.add_ram_usage( act.account, new_size - old_size );
350-
}
351-
}
352-
353-
354-
355255
void apply_eosio_setabi(apply_context& context) {
356256
auto& db = context.db;
357257
auto act = context.act.data_as<setabi>();

libraries/vm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ add_subdirectory( vm_py )
22
add_subdirectory( vm_wasm )
33
add_subdirectory( vm_eth )
44
add_subdirectory( vm_native )
5+
add_subdirectory( vm_cpython )
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
set(PYTHON3 "LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/libraries/python;${CMAKE_SOURCE_DIR}/libraries/python/dist/bin/python3")
2+
3+
add_custom_command(
4+
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/vm_cpython.wrap.cpp
5+
COMMAND ${PYTHON3} -m cython --cplus ${CMAKE_CURRENT_SOURCE_DIR}/vm_cpython.pyx -o ${CMAKE_CURRENT_SOURCE_DIR}/vm_cpython.wrap.cpp
6+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/vm_cpython.pyx
7+
)
8+
9+
add_library(vm_cpython SHARED
10+
vm_cpython.wrap.cpp
11+
vm_cpython.cpp)
12+
13+
target_link_libraries(vm_cpython PRIVATE eosiolib_native db_api python3)
14+
15+
target_include_directories(vm_cpython PRIVATE ${Boost_INCLUDE_DIR}
16+
# PRIVATE ${CMAKE_SOURCE_DIR}/contracts/libc++/upstream/include
17+
# PRIVATE ${CMAKE_SOURCE_DIR}/contracts/libc++/include/libc++/upstream/include
18+
# PRIVATE ${CMAKE_SOURCE_DIR}/contracts/libc++/musl/include/musl/upstream/include
19+
# PRIVATE ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include
20+
PRIVATE ${CMAKE_SOURCE_DIR}/externals/magic_get/include
21+
PRIVATE ${CMAKE_BINARY_DIR}/libraries/appbase/include
22+
PUBLIC ${CMAKE_SOURCE_DIR}/libraries/chainbase/include
23+
PUBLIC ${CMAKE_SOURCE_DIR}/libraries/softfloat/source/include
24+
25+
PUBLIC ${CMAKE_SOURCE_DIR}/libraries/python/Include
26+
PUBLIC ${CMAKE_SOURCE_DIR}/libraries/python
27+
28+
PRIVATE ${CMAKE_BINARY_DIR}/libraries/fc/include
29+
# PRIVATE ${CMAKE_BINARY_DIR}/libraries/chain/include
30+
PRIVATE ${CMAKE_SOURCE_DIR}/contracts
31+
)
32+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "vm_cpython.h"
2+
3+
#include <Python.h>
4+
5+
#include <eosiolib_native/vm_api.h>
6+
7+
static struct vm_api* s_api;
8+
9+
extern "C" PyObject* PyInit_vm_cpython();
10+
11+
int init_cpython();
12+
int cpython_setcode(uint64_t account, string& code);
13+
int cpython_apply(unsigned long long receiver, unsigned long long account, unsigned long long action);
14+
15+
void get_code(uint64_t account, string& code) {
16+
size_t size;
17+
const char* _code = get_vm_api()->get_code(account, &size);
18+
code = string(_code, size);
19+
}
20+
21+
int init_cpython_() {
22+
PyInit_vm_cpython();
23+
return 1;
24+
}
25+
26+
void vm_init(struct vm_api* api) {
27+
s_api = api;
28+
vm_register_api(api);
29+
PyInit_vm_cpython();
30+
}
31+
32+
void vm_deinit() {
33+
printf("vm_native finalize\n");
34+
}
35+
36+
struct vm_api* get_vm_api() {
37+
return s_api;
38+
}
39+
40+
int vm_setcode(uint64_t account) {
41+
string code;
42+
get_code(account, code);
43+
return cpython_setcode(account, code);
44+
}
45+
46+
int vm_apply(uint64_t receiver, uint64_t account, uint64_t act) {
47+
return cpython_apply(receiver, account, act);
48+
}
49+
50+

libraries/vm/vm_cpython/vm_cpython.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <string>
2+
#include <vector>
3+
using namespace std;
4+
5+
void get_code(uint64_t account, string& code);
6+
int init_cpython_();
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from libcpp.string cimport string
2+
from libcpp.vector cimport vector
3+
from libcpp.map cimport map
4+
import os
5+
import sys
6+
import imp
7+
import logging
8+
import traceback
9+
10+
import db
11+
import eoslib
12+
13+
cdef extern from "<stdint.h>":
14+
ctypedef unsigned long long uint64_t
15+
16+
cdef extern from "vm_cpython.h":
17+
void get_code(uint64_t account, string& code)
18+
19+
sys.modules['ustruct'] = sys.modules['struct']
20+
21+
py_modules = {}
22+
23+
def _get_code(uint64_t account):
24+
cdef string code
25+
get_code(account, code)
26+
return code
27+
28+
def _load_module(account, code):
29+
try:
30+
module = imp.new_module(eoslib.n2s(account))
31+
exec(code, module.__dict__)
32+
py_modules[account] = module
33+
return module
34+
except Exception as e:
35+
logging.exception(e)
36+
return None
37+
38+
cdef extern int cpython_setcode(uint64_t account, string& code) with gil:
39+
if _load_module(account, code):
40+
return 1
41+
return 0
42+
43+
cdef extern int cpython_apply(unsigned long long receiver, unsigned long long account, unsigned long long action) with gil:
44+
try:
45+
if receiver in py_modules:
46+
py_modules[receiver].apply(receiver, account, action)
47+
return 1
48+
code = _get_code(receiver)
49+
mod = _load_module(receiver, code)
50+
if not mod:
51+
return 0
52+
mod.apply(receiver, account, action)
53+
return 1
54+
except Exception as e:
55+
logging.exception(e)
56+
return 0

libraries/vm_manager/vm_manager.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ using namespace eosio::chain;
2626
namespace bio = boost::iostreams;
2727

2828

29-
static const int TYPE_BINARYEN = 0;
30-
static const int TYPE_PY = 1;
31-
static const int TYPE_ETH = 2;
32-
static const int TYPE_WAVM = 3;
33-
static const int TYPE_IPC = 4;
34-
static const int TYPE_NATIVE = 5;
29+
static const int VM_TYPE_BINARYEN = 0;
30+
static const int VM_TYPE_PY = 1;
31+
static const int VM_TYPE_ETH = 2;
32+
static const int VM_TYPE_WAVM = 3;
33+
static const int VM_TYPE_IPC = 4;
34+
static const int VM_TYPE_NATIVE = 5;
35+
static const int VM_TYPE_CPYTHON = 6;
3536

3637

3738
namespace eosio {
@@ -153,6 +154,7 @@ static const char* vm_libs_path[] = {
153154

154155
static const char * ipc_server_lib = "../libs/libipc_server" DYLIB_SUFFIX;
155156
static const char * vm_native_lib = "../libs/libvm_native" DYLIB_SUFFIX;
157+
static const char * vm_cpython_lib = "../libs/libvm_cpython" DYLIB_SUFFIX;
156158

157159
vm_manager& vm_manager::get() {
158160
static vm_manager *mngr = nullptr;
@@ -197,11 +199,13 @@ bool vm_manager::init(struct vm_api* api) {
197199

198200
if (!get_vm_api()->has_option("no-ipc")) {
199201
if (this->api->run_mode() == 0) {//server
200-
load_vm_from_path(TYPE_IPC, ipc_server_lib);
202+
load_vm_from_path(VM_TYPE_IPC, ipc_server_lib);
201203
}
202204
}
203205

204-
load_vm_from_path(TYPE_NATIVE, vm_native_lib);
206+
load_vm_from_path(VM_TYPE_NATIVE, vm_native_lib);
207+
208+
load_vm_from_path(VM_TYPE_CPYTHON, vm_cpython_lib);
205209

206210
return true;
207211
}
@@ -356,9 +360,9 @@ int vm_manager::load_vm_from_path(int vm_type, const char* vm_path) {
356360
dlclose(__itr->second->handle);
357361
}
358362

363+
wlog("+++++++++++loading ${n1} cost: ${n2}", ("n1",vm_path)("n2", get_microseconds() - start));
359364
vm_init(this->api);
360365

361-
wlog("+++++++++++loading ${n1} cost: ${n2}", ("n1",vm_path)("n2", get_microseconds() - start));
362366
std::unique_ptr<vm_calls> calls = std::make_unique<vm_calls>();
363367
calls->version = 0;
364368
calls->handle = handle;
@@ -508,8 +512,8 @@ int vm_manager::setcode(int type, uint64_t account) {
508512
if (this->api->run_mode() == 0) {
509513
if (is_trusted_account(account)) {
510514
} else {
511-
if (vm_map.find(TYPE_IPC) != vm_map.end()) {
512-
type = TYPE_IPC;
515+
if (vm_map.find(VM_TYPE_IPC) != vm_map.end()) {
516+
type = VM_TYPE_IPC;
513517
}
514518
}
515519
}
@@ -529,9 +533,9 @@ int vm_manager::apply(int type, uint64_t receiver, uint64_t account, uint64_t ac
529533
if (is_trusted_account(account)) {
530534

531535
} else {
532-
auto itr = vm_map.find(TYPE_IPC);
536+
auto itr = vm_map.find(VM_TYPE_IPC);
533537
if (itr != vm_map.end()) {
534-
type = TYPE_IPC;
538+
type = VM_TYPE_IPC;
535539
}
536540
}
537541
return local_apply(type, receiver, account, act);
@@ -543,7 +547,7 @@ int vm_manager::local_apply(int type, uint64_t receiver, uint64_t account, uint6
543547
load_vm_from_ram(type, vm_names[type]);
544548
}
545549
*/
546-
if (vm_map[TYPE_NATIVE]->apply(receiver, account, act)) {
550+
if (vm_map[VM_TYPE_NATIVE]->apply(receiver, account, act)) {
547551
return 1;
548552
}
549553

@@ -580,7 +584,7 @@ int vm_manager::local_apply(int type, uint64_t receiver, uint64_t account, uint6
580584
//there is a small probability that the next BP can not execute all the code in one block time
581585
//at the situation of network overloading, that may cause a fork and BP will lose some revenue
582586
//a vote on jit loading can solve this problem.
583-
if (vm_map[TYPE_WAVM]->apply(receiver, account, act)) {
587+
if (vm_map[VM_TYPE_WAVM]->apply(receiver, account, act)) {
584588
return 1;
585589
}
586590
}

0 commit comments

Comments
 (0)