def serialize(self): return b''.join(( self.prev_hash, pack_le_uint32(self.prev_idx), pack_varbytes(self.script), pack_le_uint32(self.sequence), ))
def serialize(self): return b''.join(( self.keyimage, self.ringsize, pack_varbytes(self.script), pack_le_uint32(self.sequence), ))
def serialize(self): return b''.join( (pack_le_int32(self.version), pack_varint(len(self.inputs)), b''.join(tx_in.serialize() for tx_in in self.inputs), pack_varint(len(self.outputs)), b''.join(tx_out.serialize() for tx_out in self.outputs), pack_le_uint32(self.locktime)))
def serialize(self): assert len(self.merkleRootMNList) == 32 res = ( pack_le_uint16(self.version) + # version pack_le_uint32(self.height) + # height self.merkleRootMNList # merkleRootMNList ) if self.version > 1: assert len(self.merkleRootQuorums) == 32 res += self.merkleRootQuorums # merkleRootQuorums return res
def push_data(cls, data): '''Returns the opcodes to push the data on the stack.''' assert isinstance(data, (bytes, bytearray)) n = len(data) if n < OpCodes.OP_PUSHDATA1: return bytes([n]) + data if n < 256: return bytes([OpCodes.OP_PUSHDATA1, n]) + data if n < 65536: return bytes([OpCodes.OP_PUSHDATA2]) + pack_le_uint16(n) + data return bytes([OpCodes.OP_PUSHDATA4]) + pack_le_uint32(n) + data
def lookup_hashX(tx_hash, tx_idx): idx_packed = pack_le_uint32(tx_idx) # Key: b'h' + compressed_tx_hash + tx_idx + tx_num # Value: hashX prefix = b'h' + tx_hash[:4] + idx_packed # Find which entry, if any, the TX_HASH matches. for db_key, hashX in self.utxo_db.iterator(prefix=prefix): tx_num_packed = db_key[-5:] tx_num, = unpack_le_uint64(tx_num_packed + bytes(3)) hash, _height = self.fs_tx_hash(tx_num) if hash == tx_hash: return hashX, idx_packed + tx_num_packed return None, None
def serialize(self): nLocktime = pack_le_uint32(self.locktime) txins = (pack_varint(len(self.inputs)) + b''.join(tx_in.serialize() for tx_in in self.inputs)) txouts = (pack_varint(len(self.outputs)) + b''.join(tx_out.serialize() for tx_out in self.outputs)) if self.tx_type: uVersion = pack_le_uint16(self.version) uTxType = pack_le_uint16(self.tx_type) vExtra = self._serialize_extra_payload() return uVersion + uTxType + txins + txouts + nLocktime + vExtra else: nVersion = pack_le_int32(self.version) return nVersion + txins + txouts + nLocktime
def spend_utxo(self, tx_hash, tx_idx): '''Spend a UTXO and return the 33-byte value. If the UTXO is not in the cache it must be on disk. We store all UTXOs so not finding one indicates a logic error or DB corruption. ''' # Fast track is it being in the cache idx_packed = pack_le_uint32(tx_idx) cache_value = self.utxo_cache.pop(tx_hash + idx_packed, None) if cache_value: return cache_value # Spend it from the DB. # Key: b'h' + compressed_tx_hash + tx_idx + tx_num # Value: hashX prefix = b'h' + tx_hash[:4] + idx_packed candidates = { db_key: hashX for db_key, hashX in self.db.utxo_db.iterator(prefix=prefix) } for hdb_key, hashX in candidates.items(): tx_num_packed = hdb_key[-5:] if len(candidates) > 1: tx_num, = unpack_le_uint64(tx_num_packed + bytes(3)) hash, _height = self.db.fs_tx_hash(tx_num) if hash != tx_hash: assert hash is not None # Should always be found continue # Key: b'u' + address_hashX + tx_idx + tx_num # Value: the UTXO value as a 64-bit unsigned integer udb_key = b'u' + hashX + hdb_key[-9:] utxo_value_packed = self.db.utxo_db.get(udb_key) if utxo_value_packed: # Remove both entries for this UTXO self.db_deletes.append(hdb_key) self.db_deletes.append(udb_key) return hashX + tx_num_packed + utxo_value_packed raise ChainError('UTXO {} / {:,d} not found in "h" table'.format( hash_to_hex_str(tx_hash), tx_idx))
def backup_txs(self, txs, is_unspendable): undo_info = self.db.read_undo_info(self.height) if undo_info is None: raise ChainError( 'no undo information found for height {:,d}'.format( self.height)) # Use local vars for speed in the loops put_utxo = self.utxo_cache.__setitem__ spend_utxo = self.spend_utxo script_hashX = self.coin.hashX_from_script add_touched = self.touched.add undo_entry_len = 13 + HASHX_LEN # Restore coins that had been spent # (may include coins made then spent in this block) n = 0 for tx, tx_hash in txs: for txin in tx.inputs: if txin.is_generation(): continue undo_item = undo_info[n:n + undo_entry_len] put_utxo(txin.prev_hash + pack_le_uint32(txin.prev_idx), undo_item) add_touched(undo_item[:-13]) n += undo_entry_len assert n == len(undo_info) # Remove tx outputs made in this block, by spending them. for tx, tx_hash in txs: for idx, txout in enumerate(tx.outputs): # Spend the TX outputs. Be careful with unspendable # outputs - we didn't save those in the first place. if is_unspendable(txout.pk_script): continue # Get the hashX hashX = script_hashX(txout.script) cache_value = spend_utxo(tx_hash, idx) add_touched(cache_value[:-13]) self.tx_count -= len(txs)
def _read_tx_parts(self, produce_hash=True): start = self.cursor version = self._read_le_int32() inputs = self._read_inputs() outputs = self._read_outputs() locktime = self._read_le_uint32() expiry = self._read_le_uint32() end_prefix = self.cursor witness = self._read_witness(len(inputs)) if produce_hash: # TxSerializeNoWitness << 16 == 0x10000 no_witness_header = pack_le_uint32(0x10000 | (version & 0xffff)) prefix_tx = no_witness_header + self.binary[start + 4:end_prefix] tx_hash = self.blake256(prefix_tx) else: tx_hash = None return TxDcr(version, inputs, outputs, locktime, expiry, witness), tx_hash, self.cursor - start
def backup_txs(self, txs, is_unspendable): # Prevout values, in order down the block (coinbase first if present) # undo_info is in reverse block order undo_info = self.db.read_undo_info(self.height) if undo_info is None: raise ChainError( 'no undo information found for height {:,d}'.format( self.height)) n = len(undo_info) # Use local vars for speed in the loops put_utxo = self.utxo_cache.__setitem__ spend_utxo = self.spend_utxo script_hashX = self.coin.hashX_from_script touched = self.touched undo_entry_len = 13 + HASHX_LEN for tx, tx_hash in reversed(txs): for idx, txout in enumerate(tx.outputs): # Spend the TX outputs. Be careful with unspendable # outputs - we didn't save those in the first place. if is_unspendable(txout.pk_script): continue # Get the hashX hashX = script_hashX(txout.pk_script) cache_value = spend_utxo(tx_hash, idx) touched.add(cache_value[:-13]) # Restore the inputs for txin in reversed(tx.inputs): if txin.is_generation(): continue n -= undo_entry_len undo_item = undo_info[n:n + undo_entry_len] put_utxo(txin.prev_hash + pack_le_uint32(txin.prev_idx), undo_item) touched.add(undo_item[:-13]) assert n == 0 self.tx_count -= len(txs)
def serialize(self): assert len(self.hash) == 32 return ( self.hash + # hash pack_le_uint32(self.index) # index )