#include #include #include #include #include #include #include #include #include #include #include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { const secp256k1_context *eth_context() { static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); return ctx; } //! transaction const transaction &transaction::sign(const std::string &private_key) const { return *this; } std::string transaction::serialize() const { boost::property_tree::ptree pt; pt.put("from", from); pt.put("to", to); pt.put("data", data); std::stringstream ss; boost::property_tree::json_parser::write_json(ss, pt); return ss.str(); } void transaction::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("from")) from = tx_json.get("from"); if (tx_json.count("to")) to = tx_json.get("to"); if (tx_json.count("data")) data = tx_json.get("data"); } //! raw_transaction 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; } signed_transaction raw_transaction::sign(const std::string &private_key) const { //! Prepare signed transaction signed_transaction tr; tr.nonce = nonce; tr.gas_price = gas_price; tr.gas_limit = gas_limit; tr.to = to; 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(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()); return tr; } std::string raw_transaction::serialize() const { rlp_encoder encoder; const std::string serialized = encoder.encode(remove_0x(nonce)) + encoder.encode(remove_0x(gas_price)) + encoder.encode(remove_0x(gas_limit)) + encoder.encode(remove_0x(to)) + encoder.encode(remove_0x(value)) + encoder.encode(remove_0x(data)) + encoder.encode(remove_0x(chain_id)) + encoder.encode("") + encoder.encode(""); return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); } void raw_transaction::deserialize(const std::string &raw_tx) { rlp_decoder decoder; const auto rlp_array = decoder.decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); nonce = add_0x(rlp_array.at(0)); gas_price = add_0x(rlp_array.at(1)); gas_limit = add_0x(rlp_array.at(2)); to = add_0x(rlp_array.at(3)); value = add_0x(rlp_array.at(4)); data = add_0x(rlp_array.at(5)); chain_id = add_0x(rlp_array.at(6)); } //! signed_transaction std::string signed_transaction::serialize() const { rlp_encoder encoder; const std::string serialized = encoder.encode(remove_0x(nonce)) + encoder.encode(remove_0x(gas_price)) + encoder.encode(remove_0x(gas_limit)) + encoder.encode(remove_0x(to)) + encoder.encode(remove_0x(value)) + encoder.encode(remove_0x(data)) + encoder.encode(remove_0x(v)) + encoder.encode(remove_0x(r)) + encoder.encode(remove_0x(s)); return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); } void signed_transaction::deserialize(const std::string &raw_tx) { rlp_decoder decoder; const auto rlp_array = decoder.decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); nonce = add_0x(rlp_array.at(0)); gas_price = add_0x(rlp_array.at(1)); gas_limit = add_0x(rlp_array.at(2)); to = add_0x(rlp_array.at(3)); value = add_0x(rlp_array.at(4)); data = add_0x(rlp_array.at(5)); v = add_0x(rlp_array.at(6)); r = add_0x(rlp_array.at(7)); s = add_0x(rlp_array.at(8)); } }}} // namespace graphene::peerplays_sidechain::ethereum