bool RpcServer::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res) { std::vector<Hash> vh; for (const auto& tx_hex_str : req.txs_hashes) { BinaryArray b; if (!fromHex(tx_hex_str, b)) { res.status = "Failed to parse hex representation of transaction hash"; return true; } if (b.size() != sizeof(Hash)) { res.status = "Failed, size of data mismatch"; } vh.push_back(*reinterpret_cast<const Hash*>(b.data())); } std::list<Hash> missed_txs; std::list<Transaction> txs; m_core.getTransactions(vh, txs, missed_txs); for (auto& tx : txs) { res.txs_as_hex.push_back(toHex(toBinaryArray(tx))); } for (const auto& miss_tx : missed_txs) { res.missed_tx.push_back(Common::podToHex(miss_tx)); } res.status = CORE_RPC_STATUS_OK; return true; }
bool LevinProtocol::readCommand(Command& cmd) { bucket_head2 head = { 0 }; if (!readStrict(reinterpret_cast<uint8_t*>(&head), sizeof(head))) { return false; } if (head.m_signature != LEVIN_SIGNATURE) { throw std::runtime_error("Levin signature mismatch"); } if (head.m_cb > LEVIN_DEFAULT_MAX_PACKET_SIZE) { throw std::runtime_error("Levin packet size is too big"); } BinaryArray buf; if (head.m_cb != 0) { buf.resize(head.m_cb); if (!readStrict(&buf[0], head.m_cb)) { return false; } } cmd.command = head.m_command; cmd.buf = std::move(buf); cmd.isNotify = !head.m_have_to_return_data; cmd.isResponse = (head.m_flags & LEVIN_PACKET_RESPONSE) == LEVIN_PACKET_RESPONSE; return true; }
bool BaseFunctionalTests::prepareAndSubmitBlock(TestNode& node, CryptoNote::Block&& blockTemplate) { blockTemplate.timestamp = m_nextTimestamp; m_nextTimestamp += 2 * m_currency.difficultyTarget(); BinaryArray blockBlob = CryptoNote::toBinaryArray(blockTemplate); return node.submitBlock(::Common::toHex(blockBlob.data(), blockBlob.size())); }
bool appendMergeMiningTagToExtra(std::vector<uint8_t>& tx_extra, const TransactionExtraMergeMiningTag& mm_tag) { BinaryArray blob; if (!toBinaryArray(mm_tag, blob)) { return false; } tx_extra.push_back(TX_EXTRA_MERGE_MINING_TAG); std::copy(reinterpret_cast<const uint8_t*>(blob.data()), reinterpret_cast<const uint8_t*>(blob.data() + blob.size()), std::back_inserter(tx_extra)); return true; }
bool parseAndValidateTransactionFromBinaryArray(const BinaryArray& tx_blob, Transaction& tx, Hash& tx_hash, Hash& tx_prefix_hash) { if (!fromBinaryArray(tx, tx_blob)) { return false; } //TODO: validate tx cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash); getObjectHash(*static_cast<TransactionPrefix*>(&tx), tx_prefix_hash); return true; }
bool get_block_hashing_blob(const Block& b, BinaryArray& ba) { if (!toBinaryArray(static_cast<const BlockHeader&>(b), ba)) { return false; } Hash treeRootHash = get_tx_tree_hash(b); ba.insert(ba.end(), treeRootHash.data, treeRootHash.data + 32); auto transactionCount = asBinaryArray(Tools::get_varint_data(b.transactionHashes.size() + 1)); ba.insert(ba.end(), transactionCount.begin(), transactionCount.end()); return true; }
bool append_message_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_message& message) { BinaryArray blob; if (!toBinaryArray(message, blob)) { return false; } tx_extra.reserve(tx_extra.size() + 1 + blob.size()); tx_extra.push_back(TX_EXTRA_MESSAGE_TAG); std::copy(reinterpret_cast<const uint8_t*>(blob.data()), reinterpret_cast<const uint8_t*>(blob.data() + blob.size()), std::back_inserter(tx_extra)); return true; }
const Crypto::Hash& CachedBlock::getBlockHash() const { if (!blockHash.is_initialized()) { BinaryArray blockBinaryArray = getBlockHashingBinaryArray(); if (BLOCK_MAJOR_VERSION_2 <= block.majorVersion) { const auto& parentBlock = getParentBlockHashingBinaryArray(false); blockBinaryArray.insert(blockBinaryArray.end(), parentBlock.begin(), parentBlock.end()); } blockHash = getObjectHash(blockBinaryArray); } return blockHash.get(); }
bool get_block_longhash(cn_context &context, const Block& b, Hash& res) { BinaryArray bd; if (b.majorVersion == BLOCK_MAJOR_VERSION_1 || b.majorVersion >= BLOCK_MAJOR_VERSION_4) { if (!get_block_hashing_blob(b, bd)) { return false; } } else if (b.majorVersion == BLOCK_MAJOR_VERSION_2 || b.majorVersion == BLOCK_MAJOR_VERSION_3) { if (!get_parent_block_hashing_blob(b, bd)) { return false; } } else { return false; } cn_slow_hash(context, bd.data(), bd.size(), res); return true; }
bool addExtraNonceToTransactionExtra(std::vector<uint8_t>& tx_extra, const BinaryArray& extra_nonce) { if (extra_nonce.size() > TX_EXTRA_NONCE_MAX_COUNT) { return false; } size_t start_pos = tx_extra.size(); tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size()); //write tag tx_extra[start_pos] = TX_EXTRA_NONCE; //write len ++start_pos; tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size()); //write data ++start_pos; memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size()); return true; }
bool get_block_hash(const Block& b, Hash& res) { BinaryArray ba; if (!get_block_hashing_blob(b, ba)) { return false; } // The header of block version 1 differs from headers of blocks starting from v.2 if (BLOCK_MAJOR_VERSION_2 == b.majorVersion || BLOCK_MAJOR_VERSION_3 == b.majorVersion) { BinaryArray parent_blob; auto serializer = makeParentBlockSerializer(b, true, false); if (!toBinaryArray(serializer, parent_blob)) return false; ba.insert(ba.end(), parent_blob.begin(), parent_blob.end()); } return getObjectHash(ba, res); }
bool BaseFunctionalTests::prepareAndSubmitBlock(TestNode& node, CryptoNote::Block&& blockTemplate) { blockTemplate.timestamp = m_nextTimestamp; m_nextTimestamp += 2 * m_currency.difficultyTarget(); if (blockTemplate.majorVersion >= BLOCK_MAJOR_VERSION_2) { blockTemplate.parentBlock.majorVersion = BLOCK_MAJOR_VERSION_1; blockTemplate.parentBlock.minorVersion = BLOCK_MINOR_VERSION_0; blockTemplate.parentBlock.transactionCount = 1; CryptoNote::TransactionExtraMergeMiningTag mmTag; mmTag.depth = 0; if (!CryptoNote::get_aux_block_header_hash(blockTemplate, mmTag.merkleRoot)) { return false; } blockTemplate.parentBlock.baseTransaction.extra.clear(); if (!CryptoNote::appendMergeMiningTagToExtra(blockTemplate.parentBlock.baseTransaction.extra, mmTag)) { return false; } } BinaryArray blockBlob = CryptoNote::toBinaryArray(blockTemplate); return node.submitBlock(::Common::toHex(blockBlob.data(), blockBlob.size())); }
void LevinProtocol::sendReply(uint32_t command, const BinaryArray& out, int32_t returnCode) { bucket_head2 head = { 0 }; head.m_signature = LEVIN_SIGNATURE; head.m_cb = out.size(); head.m_have_to_return_data = false; head.m_command = command; head.m_protocol_version = LEVIN_PROTOCOL_VER_1; head.m_flags = LEVIN_PACKET_RESPONSE; head.m_return_code = returnCode; BinaryArray writeBuffer; writeBuffer.reserve(sizeof(head) + out.size()); Common::VectorOutputStream stream(writeBuffer); stream.writeSome(&head, sizeof(head)); stream.writeSome(out.data(), out.size()); writeStrict(writeBuffer.data(), writeBuffer.size()); }
void LevinProtocol::sendMessage(uint32_t command, const BinaryArray& out, bool needResponse) { bucket_head2 head = { 0 }; head.m_signature = LEVIN_SIGNATURE; head.m_cb = out.size(); head.m_have_to_return_data = needResponse; head.m_command = command; head.m_protocol_version = LEVIN_PROTOCOL_VER_1; head.m_flags = LEVIN_PACKET_REQUEST; // write header and body in one operation BinaryArray writeBuffer; writeBuffer.reserve(sizeof(head) + out.size()); Common::VectorOutputStream stream(writeBuffer); stream.writeSome(&head, sizeof(head)); stream.writeSome(out.data(), out.size()); writeStrict(writeBuffer.data(), writeBuffer.size()); }
void getBinaryArrayHash(const BinaryArray& binaryArray, Crypto::Hash& hash) { cn_fast_hash(binaryArray.data(), binaryArray.size(), hash); }
void TransactionImpl::appendExtra(const BinaryArray& extraData) { checkIfSigning(); transaction.extra.insert( transaction.extra.end(), extraData.begin(), extraData.end()); }
bool Currency::constructMinerTx(uint32_t height, size_t medianSize, uint64_t alreadyGeneratedCoins, size_t currentBlockSize, uint64_t fee, const AccountPublicAddress& minerAddress, Transaction& tx, const BinaryArray& extraNonce/* = BinaryArray()*/, size_t maxOuts/* = 1*/) const { tx.inputs.clear(); tx.outputs.clear(); tx.extra.clear(); KeyPair txkey = generateKeyPair(); addTransactionPublicKeyToExtra(tx.extra, txkey.publicKey); if (!extraNonce.empty()) { if (!addExtraNonceToTransactionExtra(tx.extra, extraNonce)) { return false; } } BaseInput in; in.blockIndex = height; uint64_t blockReward; int64_t emissionChange; if (!getBlockReward(medianSize, currentBlockSize, alreadyGeneratedCoins, fee, height, blockReward, emissionChange)) { logger(INFO) << "Block is too big"; return false; } std::vector<uint64_t> outAmounts; decompose_amount_into_digits(blockReward, m_defaultDustThreshold, [&outAmounts](uint64_t a_chunk) { outAmounts.push_back(a_chunk); }, [&outAmounts](uint64_t a_dust) { outAmounts.push_back(a_dust); }); if (!(1 <= maxOuts)) { logger(ERROR, BRIGHT_RED) << "max_out must be non-zero"; return false; } while (maxOuts < outAmounts.size()) { outAmounts[outAmounts.size() - 2] += outAmounts.back(); outAmounts.resize(outAmounts.size() - 1); } uint64_t summaryAmounts = 0; for (size_t no = 0; no < outAmounts.size(); no++) { Crypto::KeyDerivation derivation = boost::value_initialized<Crypto::KeyDerivation>(); Crypto::PublicKey outEphemeralPubKey = boost::value_initialized<Crypto::PublicKey>(); bool r = Crypto::generate_key_derivation(minerAddress.viewPublicKey, txkey.secretKey, derivation); if (!(r)) { logger(ERROR, BRIGHT_RED) << "while creating outs: failed to generate_key_derivation(" << minerAddress.viewPublicKey << ", " << txkey.secretKey << ")"; return false; } r = Crypto::derive_public_key(derivation, no, minerAddress.spendPublicKey, outEphemeralPubKey); if (!(r)) { logger(ERROR, BRIGHT_RED) << "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", " << minerAddress.spendPublicKey << ")"; return false; } KeyOutput tk; tk.key = outEphemeralPubKey; TransactionOutput out; summaryAmounts += out.amount = outAmounts[no]; out.target = tk; tx.outputs.push_back(out); } if (!(summaryAmounts == blockReward)) { logger(ERROR, BRIGHT_RED) << "Failed to construct miner tx, summaryAmounts = " << summaryAmounts << " not equal blockReward = " << blockReward; return false; } tx.version = TRANSACTION_VERSION_1; //lock tx.unlockTime = height + m_minedMoneyUnlockWindow; tx.inputs.push_back(in); return true; }
bool gen_block_invalid_binary_format::generate(std::vector<test_event_entry>& events) const { BLOCK_VALIDATION_INIT_GENERATE(); std::vector<uint64_t> timestamps; std::vector<difficulty_type> cummulative_difficulties; difficulty_type cummulative_diff = 1; // Unlock blk_0 outputs Block blk_last = blk_0; assert(m_currency.minedMoneyUnlockWindow() < m_currency.difficultyWindow()); for (size_t i = 0; i < m_currency.minedMoneyUnlockWindow(); ++i) { MAKE_NEXT_BLOCK(events, blk_curr, blk_last, miner_account); timestamps.push_back(blk_curr.timestamp); cummulative_difficulties.push_back(++cummulative_diff); blk_last = blk_curr; } // Lifting up takes a while difficulty_type diffic; do { blk_last = boost::get<Block>(events.back()); diffic = m_currency.nextDifficulty(timestamps, cummulative_difficulties); if (!lift_up_difficulty(m_currency, events, timestamps, cummulative_difficulties, generator, 1, blk_last, miner_account, BLOCK_MAJOR_VERSION_1)) { return false; } std::cout << "Block #" << events.size() << ", difficulty: " << diffic << std::endl; } while (diffic < 1500); blk_last = boost::get<Block>(events.back()); MAKE_TX(events, tx_0, miner_account, miner_account, MK_COINS(120), boost::get<Block>(events[1])); DO_CALLBACK(events, "corrupt_blocks_boundary"); Block blk_test; std::vector<Crypto::Hash> tx_hashes; tx_hashes.push_back(getObjectHash(tx_0)); size_t txs_size = getObjectBinarySize(tx_0); diffic = m_currency.nextDifficulty(timestamps, cummulative_difficulties); if (!generator.constructBlockManually(blk_test, blk_last, miner_account, test_generator::bf_major_ver | test_generator::bf_diffic | test_generator::bf_timestamp | test_generator::bf_tx_hashes, BLOCK_MAJOR_VERSION_1, 0, blk_last.timestamp, Crypto::Hash(), diffic, Transaction(), tx_hashes, txs_size)) return false; BinaryArray blob = toBinaryArray(blk_test); for (size_t i = 0; i < blob.size(); ++i) { for (size_t bit_idx = 0; bit_idx < sizeof(BinaryArray::value_type) * 8; ++bit_idx) { serialized_block sr_block(blob); BinaryArray::value_type& ch = sr_block.data[i]; ch ^= 1 << bit_idx; events.push_back(sr_block); } } DO_CALLBACK(events, "check_all_blocks_purged"); return true; }