#include #include #include #include #include #include #include #include #include #include #include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { namespace { int is_even(char last_char) { switch (last_char) { case '0': return 1; case '2': return 1; case '4': return 1; case '6': return 1; case '8': return 1; case 'A': return 1; case 'C': return 1; case 'E': return 1; default: return -1; } } } 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 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; //! Calculate keccak hash of transaction bytes hash; hash.resize(32); const auto transaction_string = boost::algorithm::unhex( serialize() ); keccak_256((const unsigned char *) transaction_string.data(), transaction_string.size(), (unsigned char *) hash.data()); const bytes priv_key = parse_hex(private_key); secp256k1_ecdsa_signature sign; FC_ASSERT(secp256k1_ecdsa_sign(eth_context(), &sign, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), secp256k1_nonce_function_rfc6979, nullptr)); fc::ecc::compact_signature result; FC_ASSERT(secp256k1_ecdsa_signature_serialize_compact(eth_context(), (unsigned char*) result.begin() + 1, &sign)); 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)); bytes v; if(is_even(r.back())) v = {37}; else v = {38}; tr.v = fc::to_hex((char *)&v[0], v.size()); tr.r = fc::to_hex((char *)&r[0], r.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(nonce) + encoder.encode(gas_price) + encoder.encode(gas_limit) + encoder.encode(to) + encoder.encode(value) + encoder.encode(data) + encoder.encode(chain_id) + encoder.encode("") + encoder.encode(""); return 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(raw_tx); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); nonce = rlp_array.at(0); gas_price = rlp_array.at(1); gas_limit = rlp_array.at(2); to = rlp_array.at(3); value = rlp_array.at(4); data = rlp_array.at(5); chain_id = rlp_array.at(6); } //! signed_transaction std::string signed_transaction::serialize() const { rlp_encoder encoder; const std::string serialized = encoder.encode(nonce) + encoder.encode(gas_price) + encoder.encode(gas_limit) + encoder.encode(to) + encoder.encode(value) + encoder.encode(data) + encoder.encode(v) + encoder.encode(r) + encoder.encode(s); return 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(raw_tx); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); nonce = rlp_array.at(0); gas_price = rlp_array.at(1); gas_limit = rlp_array.at(2); to = rlp_array.at(3); value = rlp_array.at(4); data = rlp_array.at(5); v = rlp_array.at(6); r = rlp_array.at(7); s = rlp_array.at(8); } }}} // namespace graphene::peerplays_sidechain::ethereum