bool script::op_checksig(const message::transaction& parent_tx, uint32_t input_index) { if (stack_.size() < 2) return false; data_chunk pubkey = pop_stack(), signature = pop_stack(); script script_code; for (operation op: operations_) { if (op.data == signature || op.code == opcode::codeseparator) continue; script_code.push_operation(op); } elliptic_curve_key key; key.set_public_key(pubkey); uint32_t hash_type = 0; hash_type = signature.back(); signature.pop_back(); BITCOIN_ASSERT(signature.size() == 70); if (hash_type != 1) { log_error() << "Unimplemented hash_type"; return false; } if (input_index >= parent_tx.inputs.size()) { log_fatal() << "script::op_checksig() : input_index " << input_index << " is out of range."; return false; } message::transaction tx_tmp = parent_tx; // Blank all other inputs' signatures for (message::transaction_input& input: tx_tmp.inputs) input.input_script = script(); tx_tmp.inputs[input_index].input_script = script_code; hash_digest tx_hash = hash_transaction(tx_tmp, hash_type); return key.verify(tx_hash, signature); }
bool leveldb_validate_block::fetch_orphan_transaction( transaction_type& tx, size_t& tx_height, const hash_digest& tx_hash) { for (size_t orphan_iter = 0; orphan_iter <= orphan_index_; ++orphan_iter) { const block_type& orphan_block = orphan_chain_[orphan_iter]->actual(); for (const transaction_type& orphan_tx: orphan_block.transactions) { if (hash_transaction(orphan_tx) == tx_hash) { tx = orphan_tx; tx_height = fork_index_ + orphan_iter + 1; return true; } } } return false; }
bool leveldb_common::save_block( uint32_t height, const block_type& serial_block) { leveldb_transaction_batch batch; // Write block header + tx hashes data_chunk raw_block_data( 80 + 4 + serial_block.transactions.size() * hash_digest_size); // Downcast to base header type so serializer selects that. auto header_end = satoshi_save( serial_block.header, raw_block_data.begin()); BITCOIN_ASSERT(std::distance(raw_block_data.begin(), header_end) == 80); auto serial_hashes = make_serializer(header_end); // Write the number of transactions... serial_hashes.write_4_bytes(serial_block.transactions.size()); // ... And now the tx themselves. for (uint32_t tx_index = 0; tx_index < serial_block.transactions.size(); ++tx_index) { const transaction_type& block_tx = serial_block.transactions[tx_index]; const hash_digest& tx_hash = hash_transaction(block_tx); if (!save_transaction(batch, height, tx_index, tx_hash, block_tx)) { log_fatal(LOG_BLOCKCHAIN) << "Could not save transaction"; return false; } serial_hashes.write_hash(tx_hash); } BITCOIN_ASSERT(serial_hashes.iterator() == raw_block_data.begin() + 80 + 4 + serial_block.transactions.size() * hash_digest_size); data_chunk raw_height = uncast_type(height); hash_digest block_hash = hash_block_header(serial_block.header); // Write block header batch.block.Put(slice(raw_height), slice(raw_block_data)); batch.block_hash.Put(slice_block_hash(block_hash), slice(raw_height)); // Execute batches. db_.write(batch); // Sync stealth database. db_stealth_->sync(height); return true; }
bool leveldb_common::get_transaction(leveldb_tx_info& tx_info, const hash_digest& tx_hash, bool read_parent, bool read_tx) { // First we try to read the bytes from the database. std::string value; leveldb::Status status = db_.tx->Get( leveldb::ReadOptions(), slice(tx_hash), &value); if (status.IsNotFound()) return false; else if (!status.ok()) { log_fatal(LOG_BLOCKCHAIN) << "get_transaction(" << tx_hash << "): " << status.ToString(); return false; } // Read the parent block height and our index in that block (if neccessary). BITCOIN_ASSERT(value.size() > 8); if (read_parent) { auto deserial = make_deserializer(value.begin(), value.begin() + 8); tx_info.height = deserial.read_4_bytes(); tx_info.index = deserial.read_4_bytes(); } if (!read_tx) return true; // Read the actual transaction (if neccessary). try { BITCOIN_ASSERT(value.size() > 8); satoshi_load(value.begin() + 8, value.end(), tx_info.tx); } catch (end_of_stream) { return false; } BITCOIN_ASSERT(satoshi_raw_size(tx_info.tx) + 8 == value.size()); BITCOIN_ASSERT(hash_transaction(tx_info.tx) == tx_hash); return true; }
void block_database::store(const block_type& block) { const size_t height = index_.size(); // Write block data. const hash_digest key = hash_block_header(block.header); const size_t number_txs = block.transactions.size(); const size_t value_size = 80 + 4 + 4 + number_txs * hash_size; auto write = [&](uint8_t* data) { satoshi_save(block.header, data); auto serial = make_serializer(data + 80); serial.write_4_bytes(height); serial.write_4_bytes(number_txs); for (const transaction_type& tx: block.transactions) { const hash_digest tx_hash = hash_transaction(tx); serial.write_hash(tx_hash); } }; const position_type position = map_.store(key, value_size, write); // Write height -> position mapping. write_position(position); }
/* * Copyright (c) 2011-2013 libbitcoin developers (see AUTHORS) * * This file is part of libbitcoin. * * libbitcoin is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License with * additional permissions to the one published by the Free Software * Foundation, either version 3 of the License, or (at your option) * any later version. For more information see LICENSE. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ block_type step(const block_point& root, const block_point& head, size_t n) { std::cout << "Stepping " << n << std::endl; transaction_type coinbase_tx = create_coinbase(public_key()); const block_type* prev_blk = &head.blk; static hash_digest txh6 = null_hash; if (n == 4) { prev_blk = lookup(root, {0, 0, 0}); output_point prevout{ hash_transaction(root.prefix_chain[2].transactions[0]), 0}; transaction_type tx = construct_transaction(prevout); txh6 = hash_transaction(tx); return mine_next(*prev_blk, {coinbase_tx, tx}); } else if (n == 5) { prev_blk = lookup(root, {0, 0, 0, 0}); } else if (n == 6) { output_point prevout{ hash_transaction(root.prefix_chain[1].transactions[0]), 0}; transaction_type tx = construct_transaction(prevout); txh6 = hash_transaction(tx); return mine_next(*prev_blk, {coinbase_tx, tx}); } else if (n == 7) { BITCOIN_ASSERT(txh6 != null_hash); output_point prevout{txh6, 0}; transaction_type tx = construct_transaction(prevout); return mine_next(*prev_blk, {coinbase_tx, tx}); } else if (n == 8) { prev_blk = lookup(root, {0, 0, 0}); } else if (n == 9) { BITCOIN_ASSERT(txh6 != null_hash); output_point prevout{txh6, 0}; transaction_type tx = construct_transaction(prevout); return mine_next(*prev_blk, {coinbase_tx, tx}); } else if (n == 11) { prev_blk = lookup(root, {0, 0, 0, 1}); } else if (n == 15) { // Attempt double spend. output_point prevout{ hash_transaction(root.prefix_chain[2].transactions[0]), 0}; transaction_type tx = construct_transaction(prevout); txh6 = hash_transaction(tx); return mine_next(*prev_blk, {coinbase_tx, tx}); } else if (n == 16) { prev_blk = lookup(root, {0, 0, 0, 2, 0}); } else if (n == 20) { BITCOIN_ASSERT(txh6 != null_hash); output_point prevout{txh6, 0}; transaction_type tx = construct_transaction(prevout); return mine_next(*prev_blk, {coinbase_tx, tx}); } return mine_next(*prev_blk, {coinbase_tx}); }