diff --git a/multy_core/src/golos/golos_facade.cpp b/multy_core/src/golos/golos_facade.cpp index 568f1dc..e51dcb7 100644 --- a/multy_core/src/golos/golos_facade.cpp +++ b/multy_core/src/golos/golos_facade.cpp @@ -45,7 +45,7 @@ AccountPtr GolosFacade::make_account(const char* serialized_private_key) TransactionPtr GolosFacade::make_transaction(const Account& account) { - return TransactionPtr(new GolosTransaction(account.get_blockchain_type())); + return TransactionPtr(new GolosTransaction(account)); } void GolosFacade::validate_address( diff --git a/multy_core/src/golos/golos_transaction.cpp b/multy_core/src/golos/golos_transaction.cpp index e1cecdb..c138d7c 100644 --- a/multy_core/src/golos/golos_transaction.cpp +++ b/multy_core/src/golos/golos_transaction.cpp @@ -14,23 +14,28 @@ #include "multy_core/src/api/properties_impl.h" #include "multy_core/src/blockchain_facade_base.h" +#include "multy_core/src/api/key_impl.h" #include "multy_core/src/codec.h" #include "multy_core/src/exception.h" #include "multy_core/src/exception_stream.h" #include "multy_core/src/utility.h" +#include "third-party/portable_endian.h" + #include #include #include #include #include #include +#include namespace multy_core { namespace internal { +const BinaryDataPtr GOLOS_CHAIN_ID = decode("782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de12", CODEC_HEX); const char* ISO8601_TIME_FORMAT="%FT%T%z"; std::string format_iso8601_string(const std::time_t& time) @@ -75,7 +80,7 @@ class GolosBinaryStream : m_data() {} - void write_data(const unsigned char* data, size_t len) + void write_data(const uint8_t* data, size_t len) { if (!data) { @@ -83,6 +88,7 @@ class GolosBinaryStream } m_data.insert(m_data.end(), data, data + len); + } BinaryData get_content() const @@ -91,7 +97,7 @@ class GolosBinaryStream } private: - std::vector m_data; + std::vector m_data; }; class GolosJsonStream @@ -174,6 +180,69 @@ GolosBinaryStream& operator<<(GolosBinaryStream& stream, const GolosTransactionO return stream; } +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const BinaryData& data) +{ + stream.write_data( + reinterpret_cast(data.data), data.len); + + return stream; +} + +template +GolosBinaryStream& write_as_binary(const T& data, GolosBinaryStream& stream) +{ + stream.write_data( + reinterpret_cast(&data), sizeof(data)); + + return stream; +} + +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const uint8_t data) +{ + write_as_binary(data, stream); + + return stream; +} + +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const uint16_t data) +{ + write_as_binary(htole16(data), stream); + + return stream; +} + +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const uint32_t data) +{ + write_as_binary(htole32(data), stream); + + return stream; +} + +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const uint64_t data) +{ + write_as_binary(htole64(data), stream); + + return stream; +} + +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const std::time_t& time) +{ + stream.write_data( + reinterpret_cast(time), sizeof(time)); + + return stream; +} + +GolosBinaryStream& operator<<(GolosBinaryStream& stream, const std::string& str) +{ + stream.write_data( + reinterpret_cast(str.c_str()), str.length()); + + return stream; +} + + + class GolosTransactionTransferOperation : public GolosTransactionOperation { public: @@ -195,8 +264,30 @@ class GolosTransactionTransferOperation : public GolosTransactionOperation return TRANSFER; } - void write_to_stream(GolosBinaryStream* /*stream*/) const override + void write_to_stream(GolosBinaryStream* stream) const override { + *stream << (uint8_t)0x02; // transfer_operation id + *stream << static_cast(from.size()); + *stream << from; + *stream << static_cast(to.size()); + *stream << to; + + *stream << amount.get_value_as_uint64(); + *stream << static_cast(GOLOS_VALUE_DECIMAL_PLACES); + + std::string temp (7, '\0'); + temp.insert(0, token_name); + temp.resize(7); + *stream << temp; + *stream << static_cast(memo.size()); + if (memo.size() == 0) + { + *stream << (uint8_t)0; + } else + { + *stream << memo; + } + } void write_to_stream(GolosJsonStream* stream) const override @@ -303,8 +394,9 @@ class GolosTransactionDestination PropertyT amount; }; -GolosTransaction::GolosTransaction(BlockchainType blockchain_type) - : TransactionBase(blockchain_type), +GolosTransaction::GolosTransaction(const Account& account) + : TransactionBase(account.get_blockchain_type()), + m_account(account), m_message(), m_source(), m_destination(), @@ -408,9 +500,23 @@ void GolosTransaction::update() m_signature = make_clone(as_binary_data("FAKE GOLOS TX SIGNATURE")); } +void GolosTransaction::sign() +{ + GolosBinaryStream transaction_stream; + transaction_stream << *GOLOS_CHAIN_ID; + transaction_stream << static_cast(static_cast(*m_ref_block_num)); + transaction_stream << reinterpret_cast(m_ref_block_hash.get_value()->data)[1]; + transaction_stream << static_cast(m_expiration); + transaction_stream << (uint8_t)0x01; // count operaions + transaction_stream << *m_operation; + + m_signature = m_account.get_private_key()->sign(transaction_stream.get_content()); +} + BinaryDataPtr GolosTransaction::serialize() { update(); + sign(); const uint16_t ref_block_num = static_cast( static_cast(*m_ref_block_num)); @@ -427,8 +533,8 @@ BinaryDataPtr GolosTransaction::serialize() char buffer[1024] = {'\0'}; snprintf(buffer, sizeof(buffer), R"json( { - "ref_block_num": %ud, - "ref_block_prefix": %ud, + "ref_block_num": %u, + "ref_block_prefix": %u, "expiration": "%s", "operations": [%s], "extensions": [], @@ -442,6 +548,7 @@ BinaryDataPtr GolosTransaction::serialize() encode(*m_signature, CODEC_HEX).c_str() ); + std::cerr << buffer; return make_clone(as_binary_data(buffer)); } diff --git a/multy_core/src/golos/golos_transaction.h b/multy_core/src/golos/golos_transaction.h index e4e7539..36a7ef7 100644 --- a/multy_core/src/golos/golos_transaction.h +++ b/multy_core/src/golos/golos_transaction.h @@ -36,7 +36,7 @@ typedef std::unique_ptr GolosTransactionOperationPtr; class GolosTransaction : public TransactionBase { public: - GolosTransaction(BlockchainType blockchain_type); + GolosTransaction(const Account& account); ~GolosTransaction(); void update() override; @@ -52,8 +52,10 @@ class GolosTransaction : public TransactionBase private: void verify(); void set_expiration(const std::string&); + void sign(); private: + const Account& m_account; BinaryDataPtr m_message; GolosTransactionSourcePtr m_source; GolosTransactionDestinationPtr m_destination; diff --git a/multy_test/test_golos_account.cpp b/multy_test/test_golos_account.cpp index fd9b53b..50811aa 100644 --- a/multy_test/test_golos_account.cpp +++ b/multy_test/test_golos_account.cpp @@ -123,8 +123,8 @@ GTEST_TEST(GolosTest, private_key_sign) make_account(BLOCKCHAIN_GOLOS, "5Hq2ZdSGZokcgLoNxNGL5kHKi4e3kUUCqorgFK6T6ka7KtSvYLj", reset_sp(account)); PrivateKeyPtr prv_key = account->get_private_key(); // binary serialize TX to sign golos private key - BinaryDataPtr signature = prv_key->sign(as_binary_data(from_hex("782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de1269466c1944189" - "fb3bb5a0102096d756c7479746573740b70617368616b6c7962696b010000000000000003474f4c4f5300000000"))); + BinaryDataPtr signature = prv_key->sign(as_binary_data(from_hex("782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de1269466c194418" + "9fb3bb5a0102096d756c7479746573740b70617368616b6c7962696b010000000000000003474f4c4f5300000000"))); // signature generated form golos-core ASSERT_EQ(as_binary_data(from_hex( "1f2e6bb028760bacddd31dc9772e63240fd297ee2f9fcd29f3605aeb79f774fa4b7d1b4e6dc4a1cd6fd2d4e08b2ea2758680d6a5b1e49664522f391ff949b70018")),