def deserialize(self, serialized_hex, header_only=False): bytes_data = unhexlify(serialized_hex) self.version = read_bit32(bytes_data) self.timestamp = read_bit32(bytes_data, offset=4) self.height = read_bit32(bytes_data, offset=8) self.previous_block_hex = hexlify(bytes_data[12:8 + 12]) self.previous_block = int(self.previous_block_hex, 16) self.number_of_transactions = read_bit32(bytes_data, offset=20) self.total_amount = read_bit64(bytes_data, offset=24) self.total_fee = read_bit64(bytes_data, offset=32) self.reward = read_bit64(bytes_data, offset=40) self.payload_length = read_bit32(bytes_data, offset=48) self.payload_hash = hexlify(bytes_data[52:32 + 52]) self.generator_public_key = hexlify(bytes_data[84:33 + 84]) # TODO: test the case where block signature is not present signature_len = int(hexlify(bytes_data[118:119]), 16) signature_to = signature_len + 2 + 117 self.block_signature = hexlify(bytes_data[117:signature_to]) remaining_bytes = bytes_data[signature_to:] header_only = header_only or len(remaining_bytes) == 0 if not header_only: self._deserialize_transactions(remaining_bytes) self.id_hex = self.get_id_hex() self.id = self.get_id()
def _deserialize_transactions(self, bytes_data): transaction_lenghts = [] for x in range(self.number_of_transactions): transaction_lenghts.append(read_bit32(bytes_data, offset=x * 4)) self.transactions = [] start = 4 * self.number_of_transactions for trans_len in transaction_lenghts: serialized_hex = hexlify(bytes_data[start:start + trans_len]) self.transactions.append(Transaction(serialized_hex)) start += trans_len
def deserialize(self, serialized_hex): bytes_data = unhexlify(serialized_hex) self.version = read_bit8(bytes_data, offset=1) self.network = read_bit8(bytes_data, offset=2) self.type = read_bit8(bytes_data, offset=3) self.timestamp = read_bit32(bytes_data, offset=4) self.sender_public_key = hexlify(bytes_data[8:33 + 8]) self.fee = read_bit64(bytes_data, offset=41) self.amount = 0 self.asset = {} if Transaction.can_have_vendor_field(self.type): vendor_length = read_bit8(bytes_data, offset=49) if vendor_length > 0: self.vendor_field_hex = hexlify(bytes_data[49:vendor_length + 49]) remaining_bytes = bytes_data[49 + 1 + vendor_length:] else: remaining_bytes = bytes_data[49 + 1:] signature_bytes = self._deserialize_type(remaining_bytes) self._deserialize_signature(signature_bytes)
def read_uint32(self): return read_bit32(self)
def pop_uint32(self): data = read_bit32(self) del self[:4] return data
def _deserialize_type(self, bytes_data): # TODO: test this extensively if self.type == TRANSACTION_TYPE_TRANSFER: self.amount = read_bit64(bytes_data) self.expiration = read_bit32(bytes_data, offset=8) self.recipientId = b58encode_check(bytes_data[12:21 + 12]) return bytes_data[33:] elif self.type == TRANSACTION_TYPE_SECOND_SIGNATURE: self.asset['signature'] = {'publicKey': hexlify(bytes_data[:33])} return bytes_data[33:] elif self.type == TRANSACTION_TYPE_DELEGATE_REGISTRATION: username_length = read_bit8(bytes_data) self.asset['delegate'] = { 'username': hexlify(bytes_data[1:username_length]) } return bytes_data[username_length:] elif self.type == TRANSACTION_TYPE_VOTE: vote_length = read_bit8(bytes_data) self.asset['votes'] = [] start = 1 for x in range(vote_length): vote = hexlify(bytes_data[start:34 + start]) operator = '+' if vote[1] == '1' else '-' self.asset['votes'].append('{}{}'.format(operator, vote[2:])) start += 34 return bytes_data[start:] elif self.type == TRANSACTION_TYPE_MULTI_SIGNATURE: self.asset['multisignature']: { 'keysgroup': [], 'min': read_bit8(bytes_data), 'lifetime': read_bit8(bytes_data, offset=2), } keys_num = read_bit8(bytes_data, offset=1) start = 3 for x in range(keys_num): key = hexlify(bytes_data[start:33 + start]) self.asset['multisignature']['keysgroup'].append(key) start += 33 return bytes_data[start:] elif self.type == TRANSACTION_TYPE_IPFS: dag_length = read_bit8(bytes_data) self.asset['ipfs'] = {'dag': hexlify(bytes_data[1:dag_length])} return bytes_data[dag_length:] elif self.type == TRANSACTION_TYPE_TIMELOCK_TRANSFER: self.amount = read_bit64(bytes_data) self.timelock_type = read_bit8(bytes_data, offset=8) self.timelock = read_bit64(bytes_data, offset=9) self.recipient_id = b58encode_check(bytes_data[17:21 + 17]) return bytes_data[38:] elif self.type == TRANSACTION_TYPE_MULTI_PAYMENT: self.asset['payments'] = [] total = read_bit32(bytes_data) offset = 4 amount = 0 for x in total: payment_amount = read_bit64(bytes_data, offset=offset) self.asset['payments'].append({ 'amount': payment_amount, 'recipientId': b58encode_check(bytes_data[offset + 8:21 + offset + 8]) }) amount += payment_amount offset += 8 + 21 self.amount = payment_amount return bytes_data[offset:] elif self.type == TRANSACTION_TYPE_DELEGATE_RESIGNATION: pass else: raise Exception( 'Transaction type is invalid') # TODO: better exception