diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61afce6e4..ecc5a72ae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,8 @@ stages: - build - test - dockerize + - python-test + - deploy build-mainnet: stage: build @@ -48,6 +50,7 @@ dockerize-mainnet: IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA before_script: - docker info + - docker builder prune -a -f - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - docker build --no-cache -t $IMAGE . @@ -56,8 +59,6 @@ dockerize-mainnet: - docker rmi $IMAGE tags: - builder - when: - manual timeout: 3h @@ -78,12 +79,29 @@ build-testnet: - build/libraries/ - build/programs/ - build/tests/ + rules: + - if: $CI_COMMIT_BRANCH == "master" + when: always tags: - builder - when: - manual - timeout: - 3h + +deploy-testnet: + stage: deploy + dependencies: + - build-testnet + script: + - sudo systemctl stop witness + - rm $WORK_DIR/peerplays/witness_node || true + - cp build/programs/witness_node/witness_node $WORK_DIR/peerplays/ + - sudo systemctl restart witness + rules: + - if: $CI_COMMIT_BRANCH == "master" + when: always + environment: + name: devnet + url: $DEVNET_URL + tags: + - devnet test-testnet: stage: test @@ -119,3 +137,32 @@ dockerize-testnet: manual timeout: 3h + +test-e2e: + stage: python-test + variables: + IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA + before_script: + - docker info + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + script: + - git clone https://gitlab.com/PBSA/tools-libs/peerplays-utils.git + - cd peerplays-utils/peerplays-qa-environment + - git checkout origin/feature/python-e2e-tests-for-CI + - cd e2e-tests/ + - python3 -m venv venv + - source venv/bin/activate + - pip3 install -r requirements.txt + - python3 main.py --stop + - docker ps -a + - docker pull $IMAGE + - docker tag $IMAGE peerplays-base:latest + - docker image ls -a + - python3 main.py --start all + - docker ps -a + - python3 -m pytest test_btc_init_state.py test_hive_inital_state.py test_pp_inital_state.py + - python3 main.py --stop + - deactivate + - docker ps -a + tags: + - python-tests diff --git a/Dockerfile b/Dockerfile index 7a229aa74..8e2c76f3f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -190,7 +190,6 @@ ADD . peerplays RUN \ cd peerplays && \ git submodule update --init --recursive && \ - git symbolic-ref --short HEAD && \ git log --oneline -n 5 && \ mkdir build && \ cd build && \ diff --git a/libraries/chain/include/graphene/chain/sidechain_address_object.hpp b/libraries/chain/include/graphene/chain/sidechain_address_object.hpp index 73be44d5b..b808a23c0 100644 --- a/libraries/chain/include/graphene/chain/sidechain_address_object.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_address_object.hpp @@ -36,6 +36,15 @@ namespace graphene { namespace chain { deposit_address(""), withdraw_public_key(""), withdraw_address("") {} + + inline string get_deposit_address() const { + if(sidechain_type::ethereum != sidechain) + return deposit_address; + + auto deposit_address_lower = deposit_address; + std::transform(deposit_address_lower.begin(), deposit_address_lower.end(), deposit_address_lower.begin(), ::tolower); + return deposit_address_lower; + } }; struct by_account; @@ -76,7 +85,7 @@ namespace graphene { namespace chain { ordered_non_unique< tag, composite_key, - member, + const_mem_fun, member > > diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 872a57200..19a373deb 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -137,8 +137,9 @@ std::string rlp_encoder::encode_length(int len, int offset) { std::string rlp_encoder::hex2bytes(const std::string &s) { std::string dest; - dest.resize(s.size() / 2); - hex2bin(s.c_str(), &dest[0]); + const auto s_final = s.size() % 2 == 0 ? s : "0" + s; + dest.resize(s_final.size() / 2); + hex2bin(s_final.c_str(), &dest[0]); return dest; } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index c4db3266b..fb21a87cd 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -684,13 +684,18 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid const ethereum::signature_encoder encoder{function_signature}; #ifdef SEND_RAW_TRANSACTION + const auto data = encoder.encode(transactions); + const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]"; + ethereum::raw_transaction raw_tr; raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key)); raw_tr.gas_price = rpc_client->get_gas_price(); - raw_tr.gas_limit = rpc_client->get_gas_limit(); + raw_tr.gas_limit = rpc_client->get_estimate_gas(params); + if (raw_tr.gas_limit.empty()) + raw_tr.gas_limit = rpc_client->get_gas_limit(); raw_tr.to = wallet_contract_address; raw_tr.value = ""; - raw_tr.data = encoder.encode(transactions); + raw_tr.data = data; raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); const auto sign_tr = raw_tr.sign(get_private_key(public_key)); @@ -804,7 +809,7 @@ optional sidechain_net_handler_ethereum::estimate_withdrawal_transaction_ } const auto &public_key = son->sidechain_public_keys.at(sidechain); - const auto data = ethereum::withdrawal_encoder::encode(public_key, boost::multiprecision::uint256_t{1} * boost::multiprecision::uint256_t{10000000000}, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); + const auto data = ethereum::withdrawal_encoder::encode(public_key, boost::multiprecision::uint256_t{1} * boost::multiprecision::uint256_t{10000000000}, "0"); const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]"; const auto estimate_gas = ethereum::from_hex(rpc_client->get_estimate_gas(params)); @@ -909,8 +914,9 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe const boost::property_tree::ptree tx = tx_child.second; tx_idx = tx_idx + 1; - const std::string from = tx.get("from"); const std::string to = tx.get("to"); + std::string from = tx.get("from"); + std::transform(from.begin(), from.end(), from.begin(), ::tolower); std::string cmp_to = to; std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index e1363b0bc..f01e26051 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2773,12 +2773,21 @@ class wallet_api_impl FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son)); FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); + bool update_vote_time = false; if (approve) { FC_ASSERT(son_obj->get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", *son_obj)); + account_id_type stake_account = get_account_id(voting_account); + const auto gpos_info = _remote_db->get_gpos_info(stake_account); + const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod(); + const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start()); + const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod; + auto insert_result = voting_account_object.options.votes.insert(*son_obj->get_sidechain_vote_id(sidechain)); - if (!insert_result.second) - FC_THROW("Account ${account} has already voted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain)); + if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time)) + FC_THROW("Account ${account} was already voting for son ${son} in the current GPOS sub-period", ("account", voting_account)("son", son)); + else + update_vote_time = true; //Allow user to vote in each sub-period(Update voting time, which is reference in calculating VF) } else { @@ -2787,9 +2796,11 @@ class wallet_api_impl if (!votes_removed) FC_THROW("Account ${account} has already unvoted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain)); } + account_update_operation account_update_op; account_update_op.account = voting_account_object.id; account_update_op.new_options = voting_account_object.options; + account_update_op.extensions.value.update_last_voting_time = update_vote_time; signed_transaction tx; tx.operations.push_back( account_update_op );