Merge branch 'develop' into feature/libbitcoin-son-final

This commit is contained in:
hirunda 2022-12-19 19:21:47 +01:00
commit ffeff54090
34 changed files with 713 additions and 302 deletions

View file

@ -11,15 +11,14 @@ RUN \
apt-utils \
autoconf \
bash \
bison \
build-essential \
ca-certificates \
cmake \
dnsutils \
doxygen \
expect \
flex \
git \
graphviz \
libboost-all-dev \
libbz2-dev \
libcurl4-openssl-dev \
libncurses-dev \
@ -35,7 +34,6 @@ RUN \
ntp \
openssh-server \
pkg-config \
perl \
python3 \
python3-jinja2 \
sudo \
@ -53,6 +51,31 @@ RUN echo 'peerplays:peerplays' | chpasswd
# SSH
EXPOSE 22
#===============================================================================
# Boost setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \
cd boost_1_72_0/ && \
./bootstrap.sh && \
./b2 install
#===============================================================================
# cmake setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh && \
chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \
./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \
cmake --version
#===============================================================================
# libzmq setup
#===============================================================================
@ -85,6 +108,37 @@ RUN \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Doxygen setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
sudo apt install -y bison flex && \
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
tar -xvf Release_1_8_17.tar.gz && \
cd doxygen-Release_1_8_17 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Perl setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
tar -xvf v5.30.0.tar.gz && \
cd perl5-5.30.0 && \
./Configure -des && \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Peerplays setup
#===============================================================================
@ -106,6 +160,9 @@ ADD . peerplays
# Configure Peerplays
RUN \
cd peerplays && \
git submodule update --init --recursive && \
git symbolic-ref --short HEAD && \
git log --oneline -n 5 && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release ..

View file

@ -11,11 +11,12 @@ RUN \
apt-utils \
autoconf \
bash \
bison \
build-essential \
ca-certificates \
dnsutils \
doxygen \
expect \
flex \
git \
graphviz \
libbz2-dev \
@ -33,7 +34,6 @@ RUN \
ntp \
openssh-server \
pkg-config \
perl \
python3 \
python3-jinja2 \
sudo \
@ -58,9 +58,9 @@ EXPOSE 22
WORKDIR /home/peerplays/
RUN \
wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 && \
tar xjf boost_1_71_0.tar.bz2 && \
cd boost_1_71_0/ && \
wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \
tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \
cd boost_1_72_0/ && \
./bootstrap.sh && \
./b2 install
@ -108,6 +108,37 @@ RUN \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Doxygen setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
sudo apt install -y bison flex && \
wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \
tar -xvf Release_1_8_17.tar.gz && \
cd doxygen-Release_1_8_17 && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Perl setup
#===============================================================================
WORKDIR /home/peerplays/
RUN \
wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \
tar -xvf v5.30.0.tar.gz && \
cd perl5-5.30.0 && \
./Configure -des && \
make -j$(nproc) install && \
ldconfig
#===============================================================================
# Peerplays setup
#===============================================================================
@ -129,6 +160,9 @@ ADD . peerplays
# Configure Peerplays
RUN \
cd peerplays && \
git submodule update --init --recursive && \
git symbolic-ref --short HEAD && \
git log --oneline -n 5 && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release ..

View file

@ -1912,7 +1912,7 @@ map<son_id_type, string> database_api_impl::get_son_network_status_by_sidechain(
if (time_point_sec(sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_down_time())) > _db.head_block_time()) {
status = "OK, irregular SON heartbeat, but not triggering SON down proposal";
} else {
status = "NOT OK, irregular SON heartbeat, triggering SON down proposal]";
status = "NOT OK, irregular SON heartbeat, triggering SON down proposal";
}
}
} else {

View file

@ -236,7 +236,7 @@ std::set<son_id_type> database::get_sons_to_be_deregistered()
// TODO : We need to add a function that returns if we can deregister SON
// i.e. with introduction of PW code, we have to make a decision if the SON
// is needed for release of funds from the PW
if (head_block_time() - stats.last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
if (head_block_time() - stats.last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
need_to_be_deregistered = false;
}
}
@ -311,7 +311,7 @@ bool database::is_son_dereg_valid( son_id_type son_id )
if(status_son_dereg_valid)
{
if(head_block_time() - son->statistics(*this).last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time()))
if(head_block_time() - son->statistics(*this).last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time()))
{
status_son_dereg_valid = false;
}

View file

@ -0,0 +1,7 @@
#ifndef HARDFORK_SIDECHAIN_DELETE_TIME
#ifdef BUILD_PEERPLAYS_TESTNET
#define HARDFORK_SIDECHAIN_DELETE_TIME (fc::time_point_sec::from_iso_string("2022-11-16T02:00:00"))
#else
#define HARDFORK_SIDECHAIN_DELETE_TIME (fc::time_point_sec::from_iso_string("2022-11-16T02:00:00"))
#endif
#endif

View file

@ -22,12 +22,14 @@ object_id_type add_sidechain_address_evaluator::do_apply(const sidechain_address
const auto &sidechain_addresses_idx = db().get_index_type<sidechain_address_index>().indices().get<by_account_and_sidechain_and_expires>();
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(op.sidechain_address_account, op.sidechain, time_point_sec::maximum()));
if (addr_itr != sidechain_addresses_idx.end())
{
//db().modify(*addr_itr, [&](sidechain_address_object &sao) {
// sao.expires = db().head_block_time();
//});
db().remove(*addr_itr);
if (addr_itr != sidechain_addresses_idx.end()) {
if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) {
db().remove(*addr_itr);
} else {
db().modify(*addr_itr, [&](sidechain_address_object &sao) {
sao.expires = db().head_block_time();
});
}
}
const auto& new_sidechain_address_object = db().create<sidechain_address_object>( [&]( sidechain_address_object& obj ){
@ -106,11 +108,14 @@ void_result delete_sidechain_address_evaluator::do_apply(const sidechain_address
{ try {
const auto& idx = db().get_index_type<sidechain_address_index>().indices().get<by_id>();
auto sidechain_address = idx.find(op.sidechain_address_id);
if(sidechain_address != idx.end()) {
//db().modify(*sidechain_address, [&](sidechain_address_object &sao) {
// sao.expires = db().head_block_time();
//});
db().remove(*sidechain_address);
if (sidechain_address != idx.end()) {
if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) {
db().remove(*sidechain_address);
} else {
db().modify(*sidechain_address, [&](sidechain_address_object &sao) {
sao.expires = db().head_block_time();
});
}
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -2,7 +2,6 @@
#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
#include <stdlib.h>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
@ -19,12 +18,16 @@ std::string base_encoder::encode_address(const std::string &value) {
std::string base_encoder::encode_string(const std::string &value) {
std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str();
data += boost::algorithm::hex(value) + std::string((64 - value.size() * 2 % 64), '0');
data += boost::algorithm::hex(value);
if (value.size() % 32 != 0) {
data += std::string((64 - value.size() * 2 % 64), '0');
}
return data;
}
//! update_owners_encoder
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const {
const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) {
std::string data = "0x" + function_signature;
data += base_encoder::encode_uint256(64);
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
@ -39,7 +42,8 @@ std::string update_owners_encoder::encode(const std::vector<std::pair<std::strin
}
//! withdrawal_encoder
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const {
const std::string withdrawal_encoder::function_signature = "e088747b"; //! withdraw(address,uint256,string)
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
std::string data = "0x" + function_signature;
data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount);
@ -49,6 +53,51 @@ std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecis
return data;
}
//! signature_encoder
signature_encoder::signature_encoder(const std::string &function_hash) :
function_signature{function_hash} {
}
std::string signature_encoder::get_function_signature_from_transaction(const std::string &transaction) {
const std::string tr = remove_0x(transaction);
if (tr.substr(0, 8) == update_owners_encoder::function_signature)
return update_owners_function_signature;
if (tr.substr(0, 8) == withdrawal_encoder::function_signature)
return withdrawal_function_signature;
return "";
}
std::string signature_encoder::encode(const std::vector<encoded_sign_transaction> &transactions) const {
std::string data = "0x" + function_signature;
data += base_encoder::encode_uint256(32);
data += base_encoder::encode_uint256(transactions.size());
size_t offset = (transactions.size()) * 32;
for (const auto &transaction : transactions) {
data += base_encoder::encode_uint256(offset);
const auto transaction_data = remove_0x(transaction.data);
offset += 5 * 32 + transaction_data.size() / 2;
if (transaction_data.size() / 2 % 32 != 0) {
offset += 32 - transaction_data.size() / 2 % 32;
}
}
for (const auto &transaction : transactions) {
data += base_encoder::encode_uint256(4 * 32);
data += base_encoder::encode_address(transaction.sign.v);
data += base_encoder::encode_address(transaction.sign.r);
data += base_encoder::encode_address(transaction.sign.s);
const auto transaction_data = remove_0x(transaction.data);
data += base_encoder::encode_uint256(transaction_data.size() / 2);
data += transaction_data;
if (transaction_data.size() % 64 != 0) {
data += std::string((64 - transaction_data.size() % 64), '0');
}
}
return data;
}
//! rlp_encoder
std::string rlp_encoder::encode(const std::string &s) {
return encode_rlp(hex2bytes(s));

View file

@ -22,7 +22,43 @@ const secp256k1_context *eth_context() {
return ctx;
}
//! transaction
bytes keccak_hash(const std::string &data) {
bytes hash;
hash.resize(32);
const auto transaction_string = boost::algorithm::unhex(remove_0x(data));
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
return hash;
}
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key) {
const bytes priv_key = parse_hex(private_key);
int recid = 0;
secp256k1_ecdsa_recoverable_signature sig;
FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL));
fc::ecc::compact_signature result;
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig));
unsigned int v = recid + from_hex<unsigned int>(chain_id) * 2 + 35;
bytes r;
for (int i = 1; i < 33; i++)
r.emplace_back((char)result.at(i));
bytes s;
for (int i = 33; i < 65; i++)
s.emplace_back((char)result.at(i));
signature eth_sig;
eth_sig.v = to_hex(v);
eth_sig.r = fc::to_hex((char *)&r[0], r.size());
eth_sig.s = fc::to_hex((char *)&s[0], s.size());
return eth_sig;
}
//! base_transaction
base_transaction::base_transaction(const std::string &raw_tx) {
}
@ -70,12 +106,7 @@ raw_transaction::raw_transaction(const std::string &raw_tx) :
}
bytes raw_transaction::hash() const {
bytes hash;
hash.resize(32);
const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize()));
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
return hash;
return keccak_hash(serialize());
}
signed_transaction raw_transaction::sign(const std::string &private_key) const {
@ -88,27 +119,10 @@ signed_transaction raw_transaction::sign(const std::string &private_key) const {
tr.value = value;
tr.data = data;
const bytes priv_key = parse_hex(private_key);
int recid = 0;
secp256k1_ecdsa_recoverable_signature sig;
FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash().data(), (const unsigned char *)priv_key.data(), NULL, NULL));
fc::ecc::compact_signature result;
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig));
bytes r;
for (int i = 1; i < 33; i++)
r.emplace_back((char)result.at(i));
bytes v = bytes{char(recid + from_hex<int>(chain_id) * 2 + 35)};
bytes s;
for (int i = 33; i < 65; i++)
s.emplace_back((char)result.at(i));
tr.r = fc::to_hex((char *)&r[0], r.size());
tr.v = fc::to_hex((char *)&v[0], v.size());
tr.s = fc::to_hex((char *)&s[0], s.size());
const auto sig = sign_hash(hash(), chain_id, private_key);
tr.v = sig.v;
tr.r = sig.r;
tr.s = sig.s;
return tr;
}
@ -157,8 +171,8 @@ signed_transaction::signed_transaction(const std::string &raw_tx) :
std::string signed_transaction::recover(const std::string &chain_id) const {
fc::ecc::compact_signature input64;
fc::from_hex(r, (char *)&input64.at(1), 32);
fc::from_hex(v, (char *)&input64.at(0), 1);
int recid = input64.at(0) - from_hex<int>(chain_id) * 2 - 35;
const int recid = from_hex<unsigned int>(v) - from_hex<unsigned int>(chain_id) * 2 - 35;
fc::from_hex(std::to_string(recid), (char *)&input64.at(0), 1);
fc::from_hex(s, (char *)&input64.at(33), 32);
secp256k1_ecdsa_recoverable_signature sig;
@ -196,8 +210,8 @@ std::string signed_transaction::serialize() const {
rlp_encoder::encode(remove_0x(value)) +
rlp_encoder::encode(remove_0x(data)) +
rlp_encoder::encode(remove_0x(v)) +
rlp_encoder::encode(remove_0x(r)) +
rlp_encoder::encode(remove_0x(s));
rlp_encoder::encode(remove_leading_00(remove_0x(r))) +
rlp_encoder::encode(remove_leading_00(remove_0x(s)));
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
}
@ -220,9 +234,9 @@ void signed_transaction::deserialize(const std::string &raw_tx) {
boost::algorithm::to_lower(data);
v = add_0x(rlp_array.at(6));
boost::algorithm::to_lower(v);
r = add_0x(rlp_array.at(7));
r = add_0x(add_leading_00(rlp_array.at(7)));
boost::algorithm::to_lower(r);
s = add_0x(rlp_array.at(8));
s = add_0x(add_leading_00(rlp_array.at(8)));
boost::algorithm::to_lower(s);
}

View file

@ -1,5 +1,36 @@
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
signature::signature(const std::string &sign) {
deserialize(sign);
}
std::string signature::serialize() const {
boost::property_tree::ptree pt;
pt.put("v", v);
pt.put("r", r);
pt.put("s", s);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
void signature::deserialize(const std::string &raw_tx) {
std::stringstream ss_tx(raw_tx);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("v"))
v = tx_json.get<std::string>("v");
if (tx_json.count("r"))
r = tx_json.get<std::string>("r");
if (tx_json.count("s"))
s = tx_json.get<std::string>("s");
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -49,4 +49,24 @@ std::string remove_0x(const std::string &s) {
return s;
}
std::string add_leading_00(const std::string &s) {
std::string result = s;
while (result.size() < 64) {
result = "00" + result;
}
return result;
}
std::string remove_leading_00(const std::string &s) {
std::string result = s;
while (result.size() > 1 && result.substr(0, 2) == "00") {
result = result.substr(2);
}
return result;
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -4,8 +4,18 @@
#include <string>
#include <vector>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[])
struct encoded_sign_transaction {
std::string data;
signature sign;
};
class base_encoder {
public:
static std::string encode_uint256(boost::multiprecision::uint256_t value);
@ -15,16 +25,27 @@ public:
class update_owners_encoder {
public:
const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
static const std::string function_signature;
std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const;
static std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id);
};
class withdrawal_encoder {
public:
const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string)
static const std::string function_signature;
std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const;
static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
};
class signature_encoder {
public:
const std::string function_signature;
signature_encoder(const std::string &function_hash);
static std::string get_function_signature_from_transaction(const std::string &transaction);
std::string encode(const std::vector<encoded_sign_transaction> &transactions) const;
};
class rlp_encoder {
@ -39,35 +60,4 @@ private:
static void hex2bin(const char *src, char *target);
};
/*class ethereum_function_call_encoder {
public:
enum operation_t {
OPERATION_CALL,
OPERATION_DELEGATE_CALL
};
static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001";
std::string encode_function_signature(const std::string &function_signature);
std::string encode_address(const std::string &addr);
std::string encode_uint256(const std::string &value);
std::string encode_uint8(uint8_t value);
std::string encode_bytes(const std::string &values);
};
class safe_transaction_encoder {
public:
static constexpr const char *const default_safe_tx_gas = "0";
static constexpr const char *const default_data_gas = "0";
static constexpr const char *const default_gas_price = "0";
static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000";
static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000";
std::string create_safe_address(const std::vector<std::string> &owner_addresses, uint32_t threshold);
std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver);
private:
ethereum_function_call_encoder m_ethereum_function_call_encoder;
};*/
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -8,6 +8,9 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes keccak_hash(const std::string &data);
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key);
class base_transaction {
public:
base_transaction() = default;
@ -75,89 +78,3 @@ public:
};
}}} // namespace graphene::peerplays_sidechain::ethereum
// Example 1
//{
// "blockHash": "0x64a6706ecaf5a97b7f3e047abb20ff223ce82c6994d80e68fdb1fdfb38d0209c",
// "blockNumber": "0xe5827c",
// "from": "0x8614c67e085f2334010f2a28e806c6f1cc176d12",
// "gas": "0x38822",
// "gasPrice": "0xce42cba69",
// "maxFeePerGas": "0xddb4d8d16",
// "maxPriorityFeePerGas": "0x3b9aca00",
// "hash": "0xeac92ea09fa8eb3ca2fb0d156cceb38ae69d4345869d41e8e49d5ecbcbb622dc",
// "input": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000",
// "nonce": "0x32",
// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
// "transactionIndex": "0xb6",
// "value": "0x2514d9d7d7d8000",
// "type": "0x2",
// "accessList": [],
// "chainId": "0x1",
// "v": "0x1",
// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c",
// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//}
//
//"0xf9021332850ce42cba69830388229468b3465833fb72a70ecdf485e0e4c7bd8665fc458802514d9d7d7d8000b901a45ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde0312150000000000000000000000000000000000000000000000000000000001a02f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28ca0782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//
//{
// "nonce": 50,
// "gasPrice": {
// "_hex": "0x0ce42cba69"
// },
// "gasLimit": {
// "_hex": "0x038822"
// },
// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
// "value": {
// "_hex": "0x02514d9d7d7d8000"
// },
// "data": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000",
// "v": 1,
// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c",
// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//}
// Example 2
//{
// "blockHash": "0xe2ae3afd86dc7343c7fb753441447a0a51bb19499325ad6e278256f0cd1b5894",
// "blockNumber": "0xe58271",
// "from": "0xb895ade6d337fbb8cb97f2ea7da43106c7f5cc26",
// "gas": "0x5208",
// "gasPrice": "0xe6f3b322e",
// "maxFeePerGas": "0x1322455fd3",
// "maxPriorityFeePerGas": "0x53724e00",
// "hash": "0xed29b56e52ad2d452e25b8ec70c37f59d935cd6d0f8fe8e83b256f3ffdfd3fce",
// "input": "0x",
// "nonce": "0x37",
// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373",
// "transactionIndex": "0x8a",
// "value": "0x4563918244f40000",
// "type": "0x2",
// "accessList": [],
// "chainId": "0x1",
// "v": "0x0",
// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c",
// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//}
//
//"0xf86c37850e6f3b322e82520894176386b6ffc469ac049f9ec1f6cc0efd1d09b373884563918244f400008000a0dcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4ca028c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//
//{
// "nonce": 55,
// "gasPrice": {
// "_hex": "0x0e6f3b322e"
// },
// "gasLimit": {
// "_hex": "0x5208"
// },
// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373",
// "value": {
// "_hex": "0x4563918244f40000"
// },
// "data": "0x",
// "v": 0,
// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c",
// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//}

View file

@ -9,4 +9,17 @@ typedef uint64_t network_id_type;
using bytes = std::vector<char>;
class signature {
public:
std::string v;
std::string r;
std::string s;
signature() = default;
signature(const std::string &sign);
std::string serialize() const;
void deserialize(const std::string &sign);
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -14,13 +14,19 @@ std::string add_0x(const std::string &s);
std::string remove_0x(const std::string &s);
std::string add_leading_00(const std::string &s);
std::string remove_leading_00(const std::string &s);
template <typename T>
std::string to_hex(const T &val) {
std::string to_hex(const T &val, bool add_front_zero = true) {
std::stringstream stream;
stream << std::hex << val;
std::string result(stream.str());
if (result.size() % 2)
result = "0" + result;
if (add_front_zero) {
if (result.size() % 2)
result = "0" + result;
}
return result;
}

View file

@ -54,6 +54,7 @@ public:
void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id);
bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id);
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -26,9 +26,10 @@ public:
std::shared_ptr<detail::sidechain_api_impl> my;
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
};
}} // namespace graphene::peerplays_sidechain
FC_API(graphene::peerplays_sidechain::sidechain_api,
(get_son_listener_log))
(get_son_listener_log)(estimate_withdrawal_transaction_fee))

View file

@ -20,10 +20,11 @@ public:
sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
virtual ~sidechain_net_handler();
sidechain_type get_sidechain();
std::vector<std::string> get_sidechain_deposit_addresses();
std::vector<std::string> get_sidechain_withdraw_addresses();
std::string get_private_key(std::string public_key);
sidechain_type get_sidechain() const;
std::vector<std::string> get_sidechain_deposit_addresses() const;
std::vector<std::string> get_sidechain_withdraw_addresses() const;
std::vector<sidechain_transaction_object> get_sidechain_transaction_objects(sidechain_transaction_status status) const;
std::string get_private_key(std::string public_key) const;
bool proposal_exists(int32_t operation_tag, const object_id_type &object_id, boost::optional<chain::operation &> proposal_op = boost::none);
bool signer_expected(const sidechain_transaction_object &sto, son_id_type signer);
@ -50,6 +51,7 @@ public:
void add_to_son_listener_log(std::string trx_id);
std::vector<std::string> get_son_listener_log();
virtual optional<asset> estimate_withdrawal_transaction_fee() const = 0;
protected:
peerplays_sidechain_plugin &plugin;

View file

@ -188,6 +188,7 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::string bitcoin_node_ip;

View file

@ -15,18 +15,21 @@ class ethereum_rpc_client : public rpc_client {
public:
ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
std::string admin_node_info();
std::string eth_blockNumber();
std::string eth_get_block_by_number(std::string block_number, bool full_block);
std::string eth_get_logs(std::string wallet_contract_address);
std::string eth_chainId();
std::string net_version();
std::string eth_get_transaction_count(const std::string &params);
std::string eth_gas_price();
std::string eth_estimateGas(const std::string &params);
std::string get_chain_id();
std::string get_network_id();
std::string get_nonce(const std::string &address);
std::string get_gas_price();
std::string get_gas_limit();
std::string get_estimate_gas(const std::string &params);
std::string eth_send_transaction(const std::string &params);
std::string eth_send_raw_transaction(const std::string &params);
@ -46,6 +49,7 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::string rpc_url;
@ -69,7 +73,7 @@ private:
boost::signals2::signal<void(const std::string &)> event_received;
void schedule_ethereum_listener();
void ethereum_listener_loop();
void handle_event(const std::string &event_data);
void handle_event(const std::string &block_number);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -45,6 +45,7 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::string rpc_url;

View file

@ -19,6 +19,7 @@ public:
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
};

View file

@ -48,6 +48,7 @@ public:
void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id);
bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id);
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
void schedule_heartbeat_loop();
void heartbeat_loop();
@ -631,6 +632,15 @@ std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin_im
return result;
}
optional<asset> peerplays_sidechain_plugin_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
if (!net_handlers.at(sidechain)) {
wlog("Net handler is null for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>();
}
return net_handlers.at(sidechain)->estimate_withdrawal_transaction_fee();
}
void peerplays_sidechain_plugin_impl::approve_proposals(sidechain_type sidechain) {
// prevent approving duplicate proposals with lock for parallel execution.
// We can have the same propsals, but in the case of parallel execution we can run
@ -927,4 +937,8 @@ std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin::g
return my->get_son_listener_log();
}
optional<asset> peerplays_sidechain_plugin::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
return my->estimate_withdrawal_transaction_fee(sidechain);
}
}} // namespace graphene::peerplays_sidechain

View file

@ -12,6 +12,7 @@ public:
std::shared_ptr<graphene::peerplays_sidechain::peerplays_sidechain_plugin> get_plugin();
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain);
private:
app::application &app;
@ -32,6 +33,10 @@ std::map<sidechain_type, std::vector<std::string>> sidechain_api_impl::get_son_l
return get_plugin()->get_son_listener_log();
}
optional<asset> sidechain_api_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
return get_plugin()->estimate_withdrawal_transaction_fee(sidechain);
}
} // namespace detail
sidechain_api::sidechain_api(graphene::app::application &_app) :
@ -45,4 +50,8 @@ std::map<sidechain_type, std::vector<std::string>> sidechain_api::get_son_listen
return my->get_son_listener_log();
}
optional<asset> sidechain_api::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
return my->estimate_withdrawal_transaction_fee(sidechain);
}
}} // namespace graphene::peerplays_sidechain

View file

@ -21,11 +21,11 @@ sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin
sidechain_net_handler::~sidechain_net_handler() {
}
sidechain_type sidechain_net_handler::get_sidechain() {
sidechain_type sidechain_net_handler::get_sidechain() const {
return sidechain;
}
std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses() {
std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses() const {
std::vector<std::string> result;
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
@ -38,7 +38,7 @@ std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses(
return result;
}
std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses() {
std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses() const {
std::vector<std::string> result;
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
@ -51,7 +51,20 @@ std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses
return result;
}
std::string sidechain_net_handler::get_private_key(std::string public_key) {
std::vector<sidechain_transaction_object> sidechain_net_handler::get_sidechain_transaction_objects(sidechain_transaction_status status) const {
std::vector<sidechain_transaction_object> result;
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, status));
std::for_each(idx_range.first, idx_range.second,
[&result](const sidechain_transaction_object &sto) {
result.push_back(sto);
});
return result;
}
std::string sidechain_net_handler::get_private_key(std::string public_key) const {
auto private_key_itr = private_keys.find(public_key);
if (private_key_itr != private_keys.end()) {
return private_key_itr->second;
@ -473,10 +486,9 @@ void sidechain_net_handler::process_withdrawals() {
}
void sidechain_net_handler::process_sidechain_transactions() {
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::valid));
const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::valid);
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) {
if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id(sidechain))) {
return;
}
@ -520,10 +532,9 @@ void sidechain_net_handler::process_sidechain_transactions() {
}
void sidechain_net_handler::send_sidechain_transactions() {
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::complete));
const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::complete);
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) {
if (sto.id == object_id_type(0, 0, 0)) {
return;
}
@ -555,10 +566,9 @@ void sidechain_net_handler::send_sidechain_transactions() {
}
void sidechain_net_handler::settle_sidechain_transactions() {
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_sidechain_and_status>();
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::sent));
const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::sent);
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) {
if (sto.id == object_id_type(0, 0, 0)) {
return;
}

View file

@ -1253,6 +1253,11 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
return false;
}
optional<asset> sidechain_net_handler_bitcoin::estimate_withdrawal_transaction_fee() const {
wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>{};
}
std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector<son_info> &son_pubkeys) {
using namespace bitcoin;

View file

@ -28,8 +28,9 @@ ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::stri
rpc_client(url, user_name, password, debug_rpc_calls) {
}
std::string ethereum_rpc_client::admin_node_info() {
return send_post_request("admin_nodeInfo", "", debug_rpc_calls);
std::string ethereum_rpc_client::eth_blockNumber() {
const std::string reply_str = send_post_request("eth_blockNumber", "", debug_rpc_calls);
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::eth_get_block_by_number(std::string block_number, bool full_block) {
@ -43,6 +44,10 @@ std::string ethereum_rpc_client::eth_get_logs(std::string wallet_contract_addres
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::eth_chainId() {
return send_post_request("eth_chainId", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::net_version() {
return send_post_request("net_version", "", debug_rpc_calls);
}
@ -55,18 +60,23 @@ std::string ethereum_rpc_client::eth_gas_price() {
return send_post_request("eth_gasPrice", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_estimateGas(const std::string &params) {
return send_post_request("eth_estimateGas", params, debug_rpc_calls);
}
std::string ethereum_rpc_client::get_chain_id() {
const std::string reply_str = eth_chainId();
const auto chain_id_string = retrieve_value_from_reply(reply_str, "");
return chain_id_string.empty() ? "" : std::to_string(ethereum::from_hex<long long>(chain_id_string));
}
std::string ethereum_rpc_client::get_network_id() {
const std::string reply_str = net_version();
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::get_network_id() {
const std::string reply_str = admin_node_info();
return retrieve_value_from_reply(reply_str, "protocols.eth.network");
}
std::string ethereum_rpc_client::get_nonce(const std::string &address) {
const std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]");
const std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"pending\"]");
const auto nonce_string = retrieve_value_from_reply(reply_str, "");
if (!nonce_string.empty()) {
const auto nonce_val = ethereum::from_hex<boost::multiprecision::uint256_t>(nonce_string);
@ -94,6 +104,11 @@ std::string ethereum_rpc_client::get_gas_limit() {
return std::string{};
}
std::string ethereum_rpc_client::get_estimate_gas(const std::string &params) {
const std::string reply_str = eth_estimateGas(params);
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::eth_send_transaction(const std::string &params) {
return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls);
}
@ -158,7 +173,8 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha
ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str));
last_block_received = 0;
const auto block_number = rpc_client->eth_blockNumber();
last_block_received = !block_number.empty() ? ethereum::from_hex<uint64_t>(block_number) : 0;
schedule_ethereum_listener();
event_received.connect([this](const std::string &event_data) {
std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach();
@ -569,33 +585,65 @@ std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const
std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) {
boost::property_tree::ptree pt;
boost::property_tree::ptree pt_array;
std::vector<ethereum::encoded_sign_transaction> transactions;
for (const auto &signature : sto.signatures) {
const auto &transaction = signature.second;
//! Check if we have this signed transaction, if not, don't send it
if (transaction.empty())
if (signature.second.empty())
continue;
ethereum::encoded_sign_transaction transaction{sto.transaction, ethereum::signature{signature.second}};
transactions.emplace_back(transaction);
}
const auto &current_son = plugin.get_current_son_object(sidechain);
FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account));
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
const auto function_signature = ethereum::signature_encoder::get_function_signature_from_transaction(sto.transaction);
if (function_signature.empty()) {
elog("Function signature is empty for transaction id ${id}, transaction ${transaction}", ("id", sto.id)("transaction", sto.transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
const ethereum::signature_encoder encoder{function_signature};
#ifdef SEND_RAW_TRANSACTION
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction);
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.to = wallet_contract_address;
raw_tr.value = "";
raw_tr.data = encoder.encode(transactions);
raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id));
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(sign_tr.serialize());
#else
const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction);
ethereum::transaction raw_tr;
raw_tr.data = encoder.encode(transactions);
raw_tr.to = wallet_contract_address;
raw_tr.from = ethereum::add_0x(public_key);
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
const std::string sidechain_transaction = rpc_client->eth_send_transaction(sign_tr.serialize());
#endif
std::stringstream ss_tx(sidechain_transaction);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("result") && !tx_json.count("error")) {
boost::property_tree::ptree node;
node.put("transaction", transaction);
node.put("transaction_receipt", tx_json.get<std::string>("result"));
pt_array.push_back(std::make_pair("", node));
} else {
//! Fixme
//! How should we proceed with error in eth_send_transaction
elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
std::stringstream ss_tx(sidechain_transaction);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("result") && !tx_json.count("error")) {
boost::property_tree::ptree node;
node.put("transaction", sto.transaction);
node.put("sidechain_transaction", sidechain_transaction);
node.put("transaction_receipt", tx_json.get<std::string>("result"));
pt_array.push_back(std::make_pair("", node));
} else {
//! Fixme
//! How should we proceed with error in eth_send_transaction
elog("Error in eth send transaction for transaction id ${id}, transaction ${transaction}, sidechain_transaction ${sidechain_transaction}", ("id", sto.id)("transaction", sto.transaction)("sidechain_transaction", sidechain_transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
pt.add_child("result_array", pt_array);
@ -638,12 +686,59 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai
if (count != json.get_child("result_array").size()) {
wlog("Not all receipts received for transaction ${id}", ("id", sto.id));
return false;
} else
} else {
if (sto.object_id.is<son_wallet_id_type>()) {
settle_amount = asset(0, database.get_global_properties().parameters.eth_asset());
}
if (sto.object_id.is<son_wallet_withdraw_id_type>()) {
auto swwo = database.get<son_wallet_withdraw_object>(sto.object_id);
settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.eth_asset());
}
return true;
}
return false;
}
optional<asset> sidechain_net_handler_ethereum::estimate_withdrawal_transaction_fee() const {
const auto &gpo = database.get_global_properties();
if (gpo.active_sons.at(sidechain).empty()) {
wlog("No active sons for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>{};
}
const auto &active_son = gpo.active_sons.at(sidechain).at(0);
const auto &s_idx = database.get_index_type<son_index>().indices().get<by_id>();
const auto son = s_idx.find(active_son.son_id);
if (son == s_idx.end()) {
wlog("Can't find son for id: ${son_id}", ("son_id", active_son.son_id));
return optional<asset>{};
}
if (!son->sidechain_public_keys.contains(sidechain)) {
wlog("No public keys for current son: ${account_id}", ("account_id", son->son_account));
return optional<asset>{};
}
const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
auto asset_itr = assets_by_symbol.find("ETH");
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset matching ETH");
return optional<asset>{};
}
const auto &public_key = son->sidechain_public_keys.at(sidechain);
const auto data = ethereum::withdrawal_encoder::encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string());
const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]";
const auto estimate_gas = ethereum::from_hex<int64_t>(rpc_client->get_estimate_gas(params));
const auto gas_price = ethereum::from_hex<int64_t>(rpc_client->get_gas_price());
const auto eth_gas_fee = double(estimate_gas * gas_price) / double{1000000000000000000};
return asset_itr->amount_from_string(std::to_string(eth_gas_fee));
}
std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id) {
std::vector<std::pair<std::string, uint16_t>> owners_weights;
for (auto &son : son_pubkeys) {
@ -651,8 +746,7 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co
owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight));
}
const ethereum::update_owners_encoder encoder;
return encoder.encode(owners_weights, object_id);
return ethereum::update_owners_encoder::encode(owners_weights, object_id);
}
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
@ -660,8 +754,7 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son
}
std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
const ethereum::withdrawal_encoder encoder;
return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string());
return ethereum::withdrawal_encoder::encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string());
}
std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) {
@ -670,25 +763,11 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
#ifdef SEND_RAW_TRANSACTION
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.to = wallet_contract_address;
raw_tr.value = "";
raw_tr.data = sto.transaction;
raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id));
//! We need to change v value according to chain_id
auto signature = ethereum::sign_hash(ethereum::keccak_hash(sto.transaction), ethereum::add_0x(ethereum::to_hex(chain_id)), get_private_key(public_key));
signature.v = ethereum::to_hex(ethereum::from_hex<unsigned int>(signature.v) - 2 * chain_id - 35 + 27);
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
return sign_tr.serialize();
#else
ethereum::transaction sign_transaction;
sign_transaction.data = sto.transaction;
sign_transaction.to = wallet_contract_address;
sign_transaction.from = "0x" + public_key;
return sign_transaction.sign(get_private_key(public_key)).serialize();
#endif
return signature.serialize();
}
void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
@ -706,32 +785,43 @@ void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
void sidechain_net_handler_ethereum::ethereum_listener_loop() {
schedule_ethereum_listener();
const std::string reply = rpc_client->eth_get_block_by_number("latest", false);
const auto reply = rpc_client->eth_blockNumber();
//std::string reply = rpc_client->eth_get_logs(wallet_contract_address);
if (!reply.empty()) {
std::stringstream ss(reply);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.count("result")) {
std::string head_block_number_s = json.get<std::string>("result.number");
uint64_t head_block_number = std::strtoul(head_block_number_s.c_str(), nullptr, 16);
if (head_block_number != last_block_received) {
std::string event_data = std::to_string(head_block_number);
handle_event(event_data);
last_block_received = head_block_number;
uint64_t head_block_number = ethereum::from_hex<uint64_t>(reply);
if (head_block_number != last_block_received) {
//! Check that current block number is greater than last one
if (head_block_number < last_block_received) {
wlog("Head block ${head_block_number} is greater than last received block ${last_block_received}", ("head_block_number", head_block_number)("last_block_received", last_block_received));
return;
}
//! Send event data for all blocks that passed
for (uint64_t i = last_block_received + 1; i <= head_block_number; ++i) {
const std::string block_number = ethereum::add_0x(ethereum::to_hex(i, false));
handle_event(block_number);
}
last_block_received = head_block_number;
}
}
}
void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) {
const std::string block = rpc_client->eth_get_block_by_number("latest", true);
void sidechain_net_handler_ethereum::handle_event(const std::string &block_number) {
const std::string block = rpc_client->eth_get_block_by_number(block_number, true);
if (block != "") {
add_to_son_listener_log("BLOCK : " + event_data);
add_to_son_listener_log("BLOCK : " + block_number);
std::stringstream ss(block);
boost::property_tree::ptree block_json;
boost::property_tree::read_json(ss, block_json);
if (block_json.get<string>("result") == "null") {
wlog("No data for block ${block_number}", ("block_number", block_number));
return;
}
size_t tx_idx = -1;
for (const auto &tx_child : block_json.get_child("result.transactions")) {
boost::property_tree::ptree tx = tx_child.second;

View file

@ -256,13 +256,14 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
const std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name);
hive::authority active;
active.weight_threshold = total_weight * 2 / 3 + 1;
active.account_auths = account_auths;
hive::authority a;
a.weight_threshold = total_weight * 2 / 3 + 1;
a.account_auths = account_auths;
hive::account_update_operation auo;
auo.account = wallet_account_name;
auo.active = active;
auo.owner = a;
auo.active = a;
auo.memo_key = op_trx.operations[0].get<hive::account_update_operation>().memo_key;
hive::signed_transaction htrx;
@ -505,13 +506,14 @@ void sidechain_net_handler_hive::process_primary_wallet() {
return;
}
hive::authority active;
active.weight_threshold = total_weight * 2 / 3 + 1;
active.account_auths = account_auths;
hive::authority a;
a.weight_threshold = total_weight * 2 / 3 + 1;
a.account_auths = account_auths;
hive::account_update_operation auo;
auo.account = wallet_account_name;
auo.active = active;
auo.owner = a;
auo.active = a;
auo.memo_key = hive::public_key_type(memo_key);
const std::string block_id_str = rpc_client->get_head_block_id();
@ -546,12 +548,27 @@ void sidechain_net_handler_hive::process_primary_wallet() {
proposal_op.proposed_ops.emplace_back(swu_op);
const auto signers = [this, &prev_sw, &active_sw, &swi] {
std::vector<son_info> signers;
//! Check if we don't have any previous set of active SONs use the current one
if (prev_sw != swi.rend()) {
if (!prev_sw->sons.at(sidechain).empty())
signers = prev_sw->sons.at(sidechain);
else
signers = active_sw->sons.at(sidechain);
} else {
signers = active_sw->sons.at(sidechain);
}
return signers;
}();
sidechain_transaction_create_operation stc_op;
stc_op.payer = gpo.parameters.son_account();
stc_op.object_id = active_sw->id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
stc_op.signers = gpo.active_sons.at(sidechain);
stc_op.signers = signers;
proposal_op.proposed_ops.emplace_back(stc_op);
@ -806,6 +823,11 @@ bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_tr
return false;
}
optional<asset> sidechain_net_handler_hive::estimate_withdrawal_transaction_fee() const {
wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>{};
}
void sidechain_net_handler_hive::schedule_hive_listener() {
fc::time_point now = fc::time_point::now();
int64_t time_to_next = 1000;

View file

@ -290,4 +290,9 @@ bool sidechain_net_handler_peerplays::settle_sidechain_transaction(const sidecha
return true;
}
optional<asset> sidechain_net_handler_peerplays::estimate_withdrawal_transaction_fee() const {
wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>{};
}
}} // namespace graphene::peerplays_sidechain

View file

@ -980,13 +980,13 @@ class wallet_api
*
* @return true if the label was set, otherwise false
*/
bool set_key_label( public_key_type, string label );
bool set_key_label( public_key_type key, string label );
/** Get label of a public key.
* @param key a public key
* @return the label if already set by \c set_key_label(), or an empty string if not set
*/
string get_key_label( public_key_type )const;
string get_key_label( public_key_type key )const;
/* Get the public key associated with a given label.
* @param label a label
@ -2676,6 +2676,19 @@ class wallet_api
*/
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log() const;
/**
* @brief Estimate transaction fee for withdrawal
* @param sidechain Sidechain type (bitcoin, HIVE, etc)
* @return Transaction fee
*/
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain) const;
/**
* @brief Estimate gas fee for withdrawal transaction for ETH
* @return Gas fee in ETH
*/
std::string eth_estimate_withdrawal_transaction_fee() const;
fc::signal<void(bool)> lock_changed;
std::shared_ptr<detail::wallet_api_impl> my;
void encrypt_keys();
@ -2976,4 +2989,6 @@ FC_API( graphene::wallet::wallet_api,
(get_voters_by_id)
(get_voters)
(get_son_listener_log)
(estimate_withdrawal_transaction_fee)
(eth_estimate_withdrawal_transaction_fee)
)

View file

@ -3291,6 +3291,25 @@ public:
return sign_transaction(trx, broadcast);
} FC_CAPTURE_AND_RETHROW((order_id)) }
sidechain_type get_sidechain_type_from_asset(asset_id_type asset_id) const
{
const auto& gpo = _remote_db->get_global_properties();
if(asset_id == gpo.parameters.btc_asset())
return sidechain_type::bitcoin;
if(asset_id == gpo.parameters.eth_asset())
return sidechain_type::ethereum;
if(asset_id == gpo.parameters.hbd_asset())
return sidechain_type::hive;
if(asset_id == gpo.parameters.hive_asset())
return sidechain_type::hive;
return sidechain_type::unknown;
}
signed_transaction transfer(string from, string to, string amount,
string asset_symbol, string memo, bool broadcast = false)
{ try {
@ -3323,6 +3342,19 @@ public:
set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees);
tx.validate();
//! For sidechain withdrawal check if amount is greater than fee
if(to_id == _remote_db->get_global_properties().parameters.son_account()) {
const auto sidechain = get_sidechain_type_from_asset(asset_obj->id);
const auto transaction_fee = estimate_withdrawal_transaction_fee(sidechain);
if(transaction_fee) {
if (*transaction_fee >= xfer_op.amount) {
FC_THROW("Transaction fee: ${sidechain_fee}, is greater than transferred amount ${amount}",
("sidechain_fee", get_asset(transaction_fee->asset_id).amount_to_pretty_string(transaction_fee->amount))("amount", get_asset(xfer_op.amount.asset_id).amount_to_pretty_string(xfer_op.amount.amount)));
}
}
}
return sign_transaction(tx, broadcast);
} FC_CAPTURE_AND_RETHROW( (from)(to)(amount)(asset_symbol)(memo)(broadcast) ) }
@ -4222,6 +4254,31 @@ public:
FC_CAPTURE_AND_RETHROW()
}
optional<asset> estimate_withdrawal_transaction_fee(sidechain_type sidechain)
{
use_sidechain_api();
try
{
return (*_remote_sidechain)->estimate_withdrawal_transaction_fee(sidechain);
}
FC_CAPTURE_AND_RETHROW()
}
std::string eth_estimate_withdrawal_transaction_fee()
{
try
{
const auto transaction_fee = estimate_withdrawal_transaction_fee(sidechain_type::ethereum);
if(transaction_fee)
{
return get_asset(transaction_fee->asset_id).amount_to_pretty_string(transaction_fee->amount);
}
return "Can't get fee value";
}
FC_CAPTURE_AND_RETHROW()
}
string _wallet_filename;
wallet_data _wallet;
@ -7273,6 +7330,16 @@ std::map<sidechain_type, std::vector<std::string>> wallet_api::get_son_listener_
return my->get_son_listener_log();
}
optional<asset> wallet_api::estimate_withdrawal_transaction_fee(sidechain_type sidechain) const
{
return my->estimate_withdrawal_transaction_fee(sidechain);
}
std::string wallet_api::eth_estimate_withdrawal_transaction_fee() const
{
return my->eth_estimate_withdrawal_transaction_fee();
}
// default ctor necessary for FC_REFLECT
signed_block_with_info::signed_block_with_info( const signed_block& block )
: signed_block( block )

View file

@ -1313,7 +1313,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status, cli_fixture )
(inner_iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id))
{
BOOST_TEST_MESSAGE("status: "<< inner_iter->second);
BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]");
BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal");
}
else if((inner_iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) &&
(inner_iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) &&
@ -1342,14 +1342,14 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status, cli_fixture )
(inner_iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id))
{
BOOST_TEST_MESSAGE("status: "<< inner_iter->second);
BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]");
BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal");
}
else if((inner_iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) &&
(inner_iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) &&
(inner_iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(1).son_id))
{
BOOST_TEST_MESSAGE("status: "<< inner_iter->second);
BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]");
BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal");
}
else{
BOOST_TEST_MESSAGE("status: "<< inner_iter->second);
@ -1517,7 +1517,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture )
(iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id))
{
BOOST_TEST_MESSAGE("status: "<< iter->second);
BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]");
BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal");
}
else if((iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) &&
(iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) &&
@ -1545,14 +1545,14 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture )
(iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id))
{
BOOST_TEST_MESSAGE("status: "<< iter->second);
BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]");
BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal");
}
else if((iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) &&
(iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) &&
(iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(1).son_id))
{
BOOST_TEST_MESSAGE("status: "<< iter->second);
BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]");
BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal");
}
else{
BOOST_TEST_MESSAGE("status: "<< iter->second);

View file

@ -9,28 +9,48 @@ using namespace graphene::peerplays_sidechain::ethereum;
BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests)
BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) {
const withdrawal_encoder encoder;
const auto tx = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0");
const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0");
BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000");
const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1");
const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) {
const signature_encoder encoder{withdrawal_function_signature};
encoded_sign_transaction transaction;
transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065c4622d2ff2b2d89c5c6f8225ab0f979bc69d4fcd4fd47db757b66fb8a39e2bc5522be5d101aa11e66da78db973f136b323be10bd107ff0b648f06b4c71ef2a4f00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(update_owners_encoder_test) {
std::vector<std::pair<std::string, uint16_t>> owners_weights;
owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1);
owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1);
const update_owners_encoder encoder;
const auto tx = encoder.encode(owners_weights, "1.35.0");
const auto tx = update_owners_encoder::encode(owners_weights, "1.35.0");
BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000");
owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1);
const auto tx1 = encoder.encode(owners_weights, "1.36.1");
const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) {
const signature_encoder encoder{update_owners_function_signature};
encoded_sign_transaction transaction;
transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0x9d6086730000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006698877eafa525c1a55f6b5e0a7187dfae484c97d9f77c4421a00276a9408a3e713d24402b44c05a883142fcffa84e1a802be37c17bb360f6f4810eb0415c8bbfd000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) {
raw_transaction raw_tr;
raw_tr.nonce = "0x0";

View file

@ -244,6 +244,9 @@ BOOST_AUTO_TEST_CASE( sidechain_address_delete_test ) {
BOOST_TEST_MESSAGE("sidechain_address_delete_test");
generate_blocks(HARDFORK_SIDECHAIN_DELETE_TIME);
generate_block();
INVOKE(sidechain_address_add_test);
GET_ACTOR(alice);
@ -266,18 +269,12 @@ BOOST_AUTO_TEST_CASE( sidechain_address_delete_test ) {
sign(trx, alice_private_key);
PUSH_TX(db, trx, ~0);
}
//time_point_sec now = db.head_block_time();
generate_block();
generate_block();
{
BOOST_TEST_MESSAGE("Check sidechain_address_delete_operation results");
const auto& idx = db.get_index_type<sidechain_address_index>().indices().get<by_account_and_sidechain_and_expires>();
//BOOST_REQUIRE( idx.size() == 1 );
//auto obj = idx.find( boost::make_tuple( alice_id, sidechain_type::bitcoin, time_point_sec::maximum() ) );
//BOOST_REQUIRE( obj == idx.end() );
//auto expired_obj = idx.find( boost::make_tuple( alice_id, sidechain_type::bitcoin, now ) );
//BOOST_REQUIRE( expired_obj != idx.end() );
BOOST_REQUIRE( idx.size() == 0 );
}
}
@ -286,6 +283,9 @@ BOOST_AUTO_TEST_CASE(sidechain_address_delete_create_test) {
BOOST_TEST_MESSAGE("sidechain_address_delete_create_test");
generate_blocks(HARDFORK_SIDECHAIN_DELETE_TIME);
generate_block();
INVOKE(sidechain_address_add_test);
GET_ACTOR(alice);

View file

@ -208,9 +208,9 @@ try {
db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
{
_s.last_down_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
_s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
_s.last_down_timestamp[sidechain_type::ethereum] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
_s.last_active_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
_s.last_active_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
_s.last_active_timestamp[sidechain_type::ethereum] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
});
auto deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));