Skip to content

Commit

Permalink
Merge pull request #21 from boscore/release/3.0.x
Browse files Browse the repository at this point in the history
Release/3.0.x
  • Loading branch information
Frank-AFN authored May 2, 2020
2 parents 2ac9463 + 9509dd7 commit 748c377
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 89 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ set( CXX_STANDARD_REQUIRED ON)

set(VERSION_MAJOR 3)
set(VERSION_MINOR 0)
set(VERSION_PATCH 5)
set(VERSION_PATCH 7)

if(VERSION_SUFFIX)
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}")
Expand All @@ -55,8 +55,8 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_compile_options(-fdiagnostics-color=always)
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
message(FATAL_ERROR "Clang version must be at least 6.0!")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
message(FATAL_ERROR "Clang version must be at least 7.0!")
endif()
endif()

Expand Down
7 changes: 3 additions & 4 deletions Docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
FROM boscore/builder:v2.0.4 as builder
FROM boscore/builder:v2.0.6 as builder
ARG branch=master
ARG symbol=EOS

ENV OPENSSL_ROOT_DIR /usr/include/openssl

RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \
&& cd bos && sed -i '/add_subdirectory(tools)/c\#add_subdirectory(tools).' libraries/eos-vm/CMakeLists.txt \
&& echo "$branch:$(git rev-parse HEAD)" > /etc/boscore-version \
&& cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/boscore-version \
&& cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \
-DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \
-DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" -DENABLE_TOOLS=OFF \
&& cmake --build /tmp/build --target install

FROM ubuntu:18.04
Expand Down
4 changes: 2 additions & 2 deletions Docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ cd bos/Docker
docker build . -t boscore/bos -s BOS
```

The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.5 tag, you could do the following:
The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.7 tag, you could do the following:

```bash
docker build -t boscore/bos:v3.0.5 --build-arg branch=v3.0.5 .
docker build -t boscore/bos:v3.0.7 --build-arg branch=v3.0.7 .

```

Expand Down
30 changes: 17 additions & 13 deletions Docker/builder/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

FROM ubuntu:18.04

LABEL author="xiaobo <peterwillcn@gmail.com>" maintainer="Xiaobo <peterwillcn@gmail.com> Huang-Ming Huang <huangh@objectcomputing.com> Winlin <pcguangtao@gmail.com>" version="0.1.2" \
Expand All @@ -8,16 +9,19 @@ RUN echo 'APT::Install-Recommends 0;' >> /etc/apt/apt.conf.d/01norecommends \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y sudo wget curl net-tools ca-certificates unzip gnupg

RUN echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main" >> /etc/apt/sources.list.d/llvm.list \
RUN echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main" >> /etc/apt/sources.list.d/llvm.list \
&& wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y git-core automake autoconf libtool build-essential pkg-config libtool \
mpi-default-dev libicu-dev python-dev python3-dev libbz2-dev zlib1g-dev libssl-dev libgmp-dev \
clang-7 lld-4.0 llvm-7-dev libclang-4.0-dev ninja-build libusb-1.0-0-dev curl libcurl4-gnutls-dev \
mpi-default-dev libicu-dev python-dev python3-dev libbz2-dev zlib1g-dev libssl-dev libgmp-dev doxygen graphviz libgmp3-dev \
ninja-build libusb-1.0-0-dev curl libcurl4-gnutls-dev autotools-dev ruby \
clang-9 lldb-9 lld-9 libllvm-9-ocaml-dev libllvm9 llvm-9 llvm-9-dev llvm-9-doc llvm-9-examples llvm-9-runtime clang-9 clang-tools-9 \
clang-9-doc libclang-common-9-dev libclang-9-dev libclang1-9 clang-format-9 python-clang-9 clangd-9 libfuzzer-9-dev lldb-9 lld-9 \
libc++-9-dev libc++abi-9-dev libomp-9-dev \
&& rm -rf /var/lib/apt/lists/*

RUN update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-7/bin/clang 700 \
&& update-alternatives --install /usr/bin/clang++ clang++ /usr/lib/llvm-7/bin/clang++ 700
RUN update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-9/bin/clang 900 \
&& update-alternatives --install /usr/bin/clang++ clang++ /usr/lib/llvm-9/bin/clang++ 900

RUN wget https://cmake.org/files/v3.9/cmake-3.9.6-Linux-x86_64.sh \
&& bash cmake-3.9.6-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir --skip-license \
Expand All @@ -29,7 +33,7 @@ ENV CXX clang++
RUN wget https://dl.bintray.com/boostorg/release/1.71.0/source/boost_1_71_0.tar.bz2 -O - | tar -xj \
&& cd boost_1_71_0 \
&& ./bootstrap.sh --prefix=/usr/local \
&& echo 'using clang : 7 : clang++-7 ;' >> project-config.jam \
&& echo 'using clang : 9 : clang++-9 ;' >> project-config.jam \
&& ./b2 -d0 -j$(nproc) --with-thread --with-date_time --with-system --with-filesystem --with-program_options \
--with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine --with-iostreams toolset=clang link=static install \
&& cd .. && rm -rf boost_1_71_0
Expand All @@ -43,12 +47,12 @@ RUN wget https://github.com/mongodb/mongo-c-driver/releases/download/1.10.2/mong
&& make install \
&& cd ../../ && rm -rf mongo-c-driver-1.10.2

RUN git clone --depth 1 --single-branch --branch release_70 https://github.com/llvm-mirror/llvm.git \
&& git clone --depth 1 --single-branch --branch release_70 https://github.com/llvm-mirror/clang.git llvm/tools/clang \
&& cd llvm \
&& cmake -H. -Bbuild -GNinja -DCMAKE_INSTALL_PREFIX=/opt/wasm -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release \
&& cmake --build build --target install \
&& cd .. && rm -rf llvm
# RUN git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/llvm.git \
# && git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/clang.git llvm/tools/clang \
# && cd llvm \
# && cmake -H. -Bbuild -GNinja -DCMAKE_INSTALL_PREFIX=/opt/wasm -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release \
# && cmake --build build --target install \
# && cd .. && rm -rf llvm

RUN git clone --depth 1 -b releases/v3.3 https://github.com/mongodb/mongo-cxx-driver \
&& cd mongo-cxx-driver/build \
Expand All @@ -70,4 +74,4 @@ RUN git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git \
&& mkdir build && cd build \
&& cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. \
&& make install \
&& cd ../../ && rm -rf cppkafka
&& cd ../../ && rm -rf cppkafka
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# BOSCore - Using technology to create a trusted business ecosystem
# BOSCore - Blockchain financial center building a trusted business ecosystem.

## BOSCore Version: v3.0.5
### Basic EOSIO Version: v1.6.6 (support REX, part 2.0.x)
## BOSCore Version: v3.0.7
### Basic EOSIO Version: v1.6.6 (support REX & EOSVM, part 2.0.x)

# Background
The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader.
Expand Down
6 changes: 3 additions & 3 deletions README_CN.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# BOSCore - 用技术打造可信商业生态
# BOSCore - 区块链自由港,构建可信商业生态。

## BOSCore Version: v3.0.5
### Basic EOSIO Version: v1.6.6 (support REX, part 2.0.x)
## BOSCore Version: v3.0.7
### Basic EOSIO Version: v1.6.6 (support REX & EOSVM, part 2.0.x)

# 背景
EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。
Expand Down
17 changes: 9 additions & 8 deletions eosio_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
fi
START_MAKE=true
TIME_BEGIN=$( date -u +%s )
VERSION=1.2
VERSION=3.0.7

txtbld=$(tput bold)
bldred=${txtbld}$(tput setaf 1)
Expand Down Expand Up @@ -174,7 +174,7 @@
MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf
export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm
export CMAKE=${HOME}/opt/cmake/bin/cmake
export PATH=${HOME}/opt/mongodb/bin:$PATH
export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH
;;
"CentOS Linux")
FILE="${SOURCE_DIR}/scripts/eosio_build_centos.sh"
Expand All @@ -183,14 +183,14 @@
MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf
export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm
export CMAKE=${HOME}/opt/cmake/bin/cmake
export PATH=${HOME}/opt/mongodb/bin:$PATH
export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH
;;
"elementary OS")
FILE="${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh"
CXX_COMPILER=clang++
C_COMPILER=clang
MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf
export PATH=${HOME}/opt/mongodb/bin:$PATH
export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH
;;
"Fedora")
FILE="${SOURCE_DIR}/scripts/eosio_build_fedora.sh"
Expand All @@ -204,21 +204,21 @@
CXX_COMPILER=clang++
C_COMPILER=clang
MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf
export PATH=${HOME}/opt/mongodb/bin:$PATH
export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH
;;
"Ubuntu")
FILE="${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh"
CXX_COMPILER=clang++
C_COMPILER=clang
MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf
export PATH=${HOME}/opt/mongodb/bin:$PATH
export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH
;;
"Debian GNU/Linux")
FILE=${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh
CXX_COMPILER=clang++
C_COMPILER=clang
MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf
export PATH=${HOME}/opt/mongodb/bin:$PATH
export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH
;;
*)
printf "\\n\\tUnsupported Linux Distribution. Exiting now.\\n\\n"
Expand Down Expand Up @@ -273,7 +273,8 @@
-DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DBUILD_MONGO_DB_PLUGIN=true \
-DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \
-DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \
-DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}"
-DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" \
-DENABLE_TOOLS=OFF
then
printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building BOSCore has exited with the above error.\\n\\n"
exit -1
Expand Down
7 changes: 4 additions & 3 deletions plugins/producer_api_plugin/producer_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ using namespace eosio;
#define INVOKE_R_R(api_handle, call_name, in_param) \
auto result = api_handle.call_name(fc::json::from_string(body).as<in_param>());

#define INVOKE_R_R_O(api_handle, call_name, in_param) \
auto result = (body == "{}" ? api_handle.call_name() : api_handle.call_name(fc::json::from_string(body).as<in_param>()));

#define INVOKE_R_R_R_R(api_handle, call_name, in_param0, in_param1, in_param2) \
const auto& vs = fc::json::json::from_string(body).as<fc::variants>(); \
auto result = api_handle.call_name(vs.at(0).as<in_param0>(), vs.at(1).as<in_param1>(), vs.at(2).as<in_param2>());
Expand Down Expand Up @@ -89,9 +92,7 @@ void producer_api_plugin::plugin_startup() {
CALL(producer, producer, get_integrity_hash,
INVOKE_R_V(producer, get_integrity_hash), 201),
CALL(producer, producer, create_snapshot,
INVOKE_R_V(producer, create_snapshot), 201),
CALL(producer, producer, create_acts_snapshot,
INVOKE_R_V(producer, create_acts_snapshot), 201),
INVOKE_R_R_O(producer, create_snapshot, producer_plugin::export_snapshot_type), 201),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class producer_plugin : public appbase::plugin<producer_plugin> {
fc::optional<int32_t> subjective_cpu_leeway_us;
fc::optional<double> incoming_defer_ratio;
};

enum export_snapshot_type {
snapshot = 0, // snapshot for data to use for restoring a node
acts_snapshot = 1 // snapshot for all accounts with system token balance
};

struct whitelist_blacklist {
fc::optional< flat_set<account_name> > actor_whitelist;
Expand Down Expand Up @@ -80,12 +85,13 @@ class producer_plugin : public appbase::plugin<producer_plugin> {
void set_whitelist_blacklist(const whitelist_blacklist& params);

integrity_hash_information get_integrity_hash() const;
snapshot_information create_snapshot() const;
snapshot_information create_acts_snapshot() const;
snapshot_information create_snapshot(export_snapshot_type type=export_snapshot_type::snapshot) const;

signal<void(const chain::producer_confirmation&)> confirmed_block;
private:
std::shared_ptr<class producer_plugin_impl> my;
snapshot_information create_blocks_snapshot(chain::controller& chain) const;
snapshot_information create_acts_snapshot(chain::controller& chain) const;
};

} //eosio
Expand All @@ -95,4 +101,5 @@ FC_REFLECT(eosio::producer_plugin::greylist_params, (accounts));
FC_REFLECT(eosio::producer_plugin::whitelist_blacklist, (actor_whitelist)(actor_blacklist)(contract_whitelist)(contract_blacklist)(action_blacklist)(key_blacklist) )
FC_REFLECT(eosio::producer_plugin::integrity_hash_information, (head_block_id)(integrity_hash))
FC_REFLECT(eosio::producer_plugin::snapshot_information, (head_block_id)(snapshot_name))
FC_REFLECT_ENUM( eosio::producer_plugin::export_snapshot_type, (snapshot)(acts_snapshot) )

57 changes: 27 additions & 30 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,20 +955,7 @@ producer_plugin::integrity_hash_information producer_plugin::get_integrity_hash(
return {chain.head_block_id(), chain.calculate_integrity_hash()};
}

producer_plugin::snapshot_information producer_plugin::create_snapshot() const {
chain::controller& chain = my->chain_plug->chain();

auto reschedule = fc::make_scoped_exit([this](){
my->schedule_production_loop();
});

if (chain.pending_block_state()) {
// abort the pending block
chain.abort_block();
} else {
reschedule.cancel();
}

producer_plugin::snapshot_information producer_plugin::create_blocks_snapshot(chain::controller& chain) const {
auto head_id = chain.head_block_id();
std::string snapshot_path = (my->_snapshots_dir / fc::format_string("snapshot-${id}.bin", fc::mutable_variant_object()("id", head_id))).generic_string();

Expand All @@ -986,23 +973,9 @@ producer_plugin::snapshot_information producer_plugin::create_snapshot() const {
return {head_id, snapshot_path};
}

producer_plugin::snapshot_information producer_plugin::create_acts_snapshot() const {

chain::controller& chain = my->chain_plug->chain();

auto reschedule = fc::make_scoped_exit([this](){
my->schedule_production_loop();
});

if (chain.pending_block_state()) {
// abort the pending block
chain.abort_block();
} else {
reschedule.cancel();
}

producer_plugin::snapshot_information producer_plugin::create_acts_snapshot(chain::controller& chain) const {
auto head_id = chain.head_block_id();
std::string acts_snapshot_path = (my->_snapshots_dir / fc::format_string("acts-snapshot-${id}.txt", fc::mutable_variant_object()("id", head_id))).generic_string();
std::string acts_snapshot_path = (my->_snapshots_dir / fc::format_string("acts-snapshot-${id}.csv", fc::mutable_variant_object()("id", head_id))).generic_string();

EOS_ASSERT( !fc::is_regular_file(acts_snapshot_path), snapshot_exists_exception,
"acts-snapshot named ${name} already exists", ("name", acts_snapshot_path));
Expand All @@ -1027,6 +1000,30 @@ producer_plugin::snapshot_information producer_plugin::create_acts_snapshot() co
return {head_id, acts_snapshot_path};
}

producer_plugin::snapshot_information producer_plugin::create_snapshot(export_snapshot_type type) const {
chain::controller& chain = my->chain_plug->chain();

auto reschedule = fc::make_scoped_exit([this](){
my->schedule_production_loop();
});

if (chain.pending_block_state()) {
// abort the pending block
chain.abort_block();
} else {
reschedule.cancel();
}
switch (type) {
case export_snapshot_type::snapshot:
return this->create_blocks_snapshot(chain);
case export_snapshot_type::acts_snapshot:
return this->create_acts_snapshot(chain);
default:
elog("Not support export_snapshot_type");
}
return {};
}

optional<fc::time_point> producer_plugin_impl::calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const {
chain::controller& chain = chain_plug->chain();
const auto& hbs = chain.head_block_state();
Expand Down
20 changes: 16 additions & 4 deletions scripts/eosio_build_amazon.sh
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,20 @@ fi
printf "\\tMongo C++ driver found at /usr/local/lib64/libmongocxx-static.a.\\n"
fi

printf "\\n\\tChecking LLVM with WASM support.\\n"
if [ ! -d "${HOME}/opt/wasm/bin" ]; then
printf "\\n\\tChecking for LLVM with WASM support.\\n"
CLANG_INSTALL=false
if ! type clang > /dev/null ; then
CLANG_INSTALL=true
echo "Failed to find clang, it will install automatically."
else
CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1)
if [ "${CLANG_V}" -lt 7 ] ; then
echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically."
CLANG_INSTALL=true
fi
fi

if [ $CLANG_INSTALL == true ]; then
printf "\\tInstalling LLVM & WASM.\\n"
if ! cd "${TEMP_DIR}"
then
Expand All @@ -556,7 +568,7 @@ fi
printf "\\n\\tExiting now.\\n"
exit 1;
fi
if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git
if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/llvm.git
then
printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n"
printf "\\tExiting now.\\n\\n"
Expand All @@ -568,7 +580,7 @@ fi
printf "\\n\\tExiting now.\\n"
exit 1;
fi
if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git
if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/clang.git
then
printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n"
printf "\\tExiting now.\\n\\n"
Expand Down
Loading

0 comments on commit 748c377

Please sign in to comment.