Exemple #1
0
 def release(self, slot_id, tx_fee=DEFAULT_RELEASE_SLOT_FEE, fee_scale=DEFAULT_FEE_SCALE, timestamp=0):
     if not self.privateKey:
         msg = 'Private key required'
         pyvsystems.throw_error(msg, MissingPrivateKeyException)
     elif tx_fee < DEFAULT_RELEASE_SLOT_FEE:
         msg = 'Transaction fee must be >= %d' % DEFAULT_RELEASE_SLOT_FEE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif slot_id >= 60 or slot_id < 0:
         msg = 'Slot id must be in 0 to 59'
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif CHECK_FEE_SCALE and fee_scale != DEFAULT_FEE_SCALE:
         msg = 'Wrong fee scale (currently, fee scale must be %d).' % DEFAULT_FEE_SCALE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif not is_offline() and self.balance() < tx_fee:
         msg = 'Insufficient VSYS balance'
         pyvsystems.throw_error(msg, InsufficientBalanceException)
     else:
         if timestamp == 0:
             timestamp = int(time.time() * 1000000000)
         sData = struct.pack(">B", RELEASE_SLOT_TX_TYPE) + \
                 struct.pack(">I", slot_id) + \
                 struct.pack(">Q", tx_fee) + \
                 struct.pack(">H", fee_scale) + \
                 struct.pack(">Q", timestamp)
         signature = bytes2str(sign(self.privateKey, sData))
         data = json.dumps({
             "senderPublicKey": self.publicKey,
             "fee": tx_fee,
             "feeScale": fee_scale,
             "slotId": slot_id,
             "timestamp": timestamp,
             "signature": signature
         })
         return self.wrapper.request('/spos/broadcast/release', data)
Exemple #2
0
 def contend(self, slot_id, tx_fee=DEFAULT_CONTEND_SLOT_FEE, fee_scale=DEFAULT_FEE_SCALE, timestamp=0):
     if not self.privateKey:
         msg = 'Private key required'
         pyvsystems.throw_error(msg, MissingPrivateKeyException)
     elif CHECK_FEE_SCALE and fee_scale != DEFAULT_FEE_SCALE:
         msg = 'Wrong fee scale (currently, fee scale must be %d).' % DEFAULT_FEE_SCALE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif self.check_contend(slot_id, tx_fee):
         if timestamp == 0:
             timestamp = int(time.time() * 1000000000)
         sData = struct.pack(">B", CONTEND_SLOT_TX_TYPE) + \
                 struct.pack(">I", slot_id) + \
                 struct.pack(">Q", tx_fee) + \
                 struct.pack(">H", fee_scale) + \
                 struct.pack(">Q", timestamp)
         signature = bytes2str(sign(self.privateKey, sData))
         data = json.dumps({
             "senderPublicKey": self.publicKey,
             "fee": tx_fee,
             "feeScale": fee_scale,
             "slotId": slot_id,
             "timestamp": timestamp,
             "signature": signature
         })
         return self.wrapper.request('/spos/broadcast/contend', data)
Exemple #3
0
 def check_contend(self, slot_id, tx_fee):
     if tx_fee < DEFAULT_CONTEND_SLOT_FEE:
         msg = 'Transaction fee must be >= %d' % DEFAULT_CONTEND_SLOT_FEE
         pyvsystems.throw_error(msg, InvalidParameterException)
         return False
     if slot_id >= 60 or slot_id < 0:
         msg = 'Slot id must be in 0 to 59'
         pyvsystems.throw_error(msg, InvalidParameterException)
         return False
     if is_offline():  # if offline, skip other check
         return True
     balance_detail = self.get_info()
     min_effective_balance = MIN_CONTEND_SLOT_BALANCE + tx_fee
     if balance_detail["effective"] < min_effective_balance:
         msg = 'Insufficient VSYS balance. (The effective balance must be >= %d)' % min_effective_balance
         pyvsystems.throw_error(msg, InvalidParameterException)
         return False
     slot_info = self.chain.slot_info(slot_id)
     if not slot_info or slot_info.get("mintingAverageBalance") is None:
         msg = 'Failed to get slot minting average balance'
         pyvsystems.throw_error(msg, NetworkException)
         return False
     elif slot_info["mintingAverageBalance"] >= balance_detail["mintingAverage"]:
         msg = 'The minting average balance of slot %d is greater than or equals to yours. ' \
               'You will contend this slot failed.' % slot_id
         pyvsystems.throw_error(msg, InsufficientBalanceException)
         return False
     return True
def print_function_specification(nested_list):
    header = nested_list[0]
    all_info = nested_list[1]
    max_length = max(all_info[0] * len(item[1]) for item in all_info[1:])
    for item in header:
        if max_length < len(item):
            max_length = len(item)

    print(header[0] + " | ", end='')
    for item in header[1:]:
        if header.index(item) != (len(header) - 1):
            print(item + " " * (max_length - len(item) + 1), end='')
        else:
            print(item + " " * (max_length - len(item) + 1))

    for items in all_info[1:]:
        if len(items) != 4:
            msg = 'Textual in function is invalid!'
            pyvsystems.throw_error(msg, InvalidParameterException)
        function_id = items[0]
        return_type = items[1]
        function_name = items[2]
        para_list = items[3]
        print(function_id + " | ", end='')
        for return_name in return_type:
            print(return_name + " " * (max_length - len(return_name) + 1),
                  end='')
        print(function_name + " " * (max_length - len(function_name) + 1),
              end='')
        for item in para_list:
            if para_list.index(item) != (len(para_list) - 1):
                print(item + " " * (max_length - len(item) + 1), end='')
            else:
                print(item + " " * (max_length - len(item) + 1))
Exemple #5
0
def data_entry_from_base58_str(str_object):
    if not type(str_object) is str:
        msg = 'Input must be string'
        pyvsystems.throw_error(msg, InvalidParameterException)
    else:
        base58_str = base58.b58decode(str_object)
        return data_entries_from_bytes(base58_str)
def print_textual_from_bytes(bytes_arrays):
    all_info = []
    if len(bytes_arrays) != 3:
        msg = 'Textual is invalid!'
        pyvsystems.throw_error(msg, InvalidParameterException)
    [initializer_bytes, _] = parse_arrays(bytes_arrays[0])
    initializer_spec = specification_from_bytes(initializer_bytes, 0)
    print("Initializer Function:")
    specification_header = [
        'id', 'return_type', 'function_name', 'variables...'
    ]
    info = copy.deepcopy([specification_header, initializer_spec])
    print_function_specification(info)
    info[1].pop(0)
    all_info.append(info[1])

    [descriptor_bytes, _] = parse_arrays(bytes_arrays[1])
    descriptor_spec = specification_from_bytes(descriptor_bytes, 1)
    print("Descriptor Functions:")
    info = copy.deepcopy([specification_header, descriptor_spec])
    print_function_specification(info)
    info[1].pop(0)
    all_info.append(info[1])

    [state_var_bytes, _] = parse_arrays(bytes_arrays[2])
    state_var = specification_from_bytes(state_var_bytes, 2)
    specification_header = ['id', 'variable_name']
    print("State Variables:")
    info = copy.deepcopy([specification_header, state_var])
    print_state_var_specification(info)
    info[1].pop(0)
    all_info.append(info[1])
    return all_info
Exemple #7
0
 def height(self):
     if is_offline():
         pyvsystems.throw_error("Cannot check height in offline mode.",
                                NetworkException)
         return 0
     else:
         return self.api_wrapper.request('/blocks/height')['height']
Exemple #8
0
 def check_tx(self, tx_id, confirmations=0):
     """Confirm tx on chain.
     Return True if Transaction is fully confirmed.
     Return False if Transaction is sent but not confirmed or failed.
     Return None if Transaction does not exist!
     """
     if is_offline():
         pyvsystems.throw_error("Cannot check transaction in offline mode.", NetworkException)
         return None
     utx_res = self.chain.unconfirmed_tx(tx_id)
     if "id" in utx_res:
         logging.error("Transaction {} is pending in UTX pool.".format(tx_id))
         return False
     else:
         tx_res = self.chain.tx(tx_id)
         if tx_res.get("status") == "Success":
             tx_height = tx_res["height"]
             cur_height = self.chain.height()
             if cur_height >= tx_height + confirmations:
                 logging.debug("Transaction {} is fully confirmed.".format(tx_id))
                 return True
             else:
                 logging.info("Transaction {} is sent but not fully confirmed.".format(tx_id))
                 return False
         elif "id" not in tx_res:
             logging.error("Transaction does not exist!")
             logging.debug("Tx API response: {}".format(tx_res))
             return None
         else:
             logging.error("Transaction failed to process!")
             logging.debug("Tx API response: {}".format(tx_res))
             return False
Exemple #9
0
 def check_tx_is_unconfirmed(self, tx_id):
     utx_res = self.chain.unconfirmed_tx(tx_id)
     if "id" in utx_res:
         pyvsystems.throw_error(
             "Transaction {} is pending in UTX pool.".format(tx_id),
             InvalidStatus)
     else:
         return False
Exemple #10
0
 def balance_detail(self):
     try:
         resp = self.wrapper.request('/addresses/balance/details/%s' % self.address)
         logging.debug(resp)
         return resp
     except Exception as ex:
         msg = "Failed to get balance detail. ({})".format(ex)
         pyvsystems.throw_error(msg, NetworkException)
         return None
Exemple #11
0
 def check_node(self, other_node_host=None):
     if is_offline():
         pyvsystems.throw_error("Cannot check node in offline mode.", NetworkException)
         return False
     if other_node_host:
         res = self.chain.check_with_other_node(other_node_host)
     else:
         res = self.chain.self_check()
     # add more check if need
     return res
Exemple #12
0
 def get_connected_peers(self):
     if is_offline():
         pyvsystems.throw_error("Cannot check peers in offline mode.",
                                NetworkException)
         return []
     response = self.api_wrapper.request('/peers/connected')
     if not response.get("peers"):
         return []
     else:
         return [peer["address"] for peer in response.get("peers")]
Exemple #13
0
 def balance(self, confirmations=0):
     if is_offline():
         pyvsystems.throw_error("Cannot check balance in offline mode.", NetworkException)
         return 0
     try:
         confirmations_str = '' if confirmations == 0 else '/%d' % confirmations
         resp = self.wrapper.request('/addresses/balance/%s%s' % (self.address, confirmations_str))
         logging.debug(resp)
         return resp['balance']
     except Exception as ex:
         msg = "Failed to get balance. ({})".format(ex)
         pyvsystems.throw_error(msg, NetworkException)
         return 0
def print_functions(functions_opcode, all_info):
    trigger = all_info[0]
    execute_fun = all_info[1]
    if len(functions_opcode) != (len(trigger) + len(execute_fun)):
        msg = 'Functions are not well defined in opc and textual!'
        pyvsystems.throw_error(msg, InvalidParameterException)
    else:
        functions_spec = copy.deepcopy([trigger[0]] + execute_fun)
        for i in range(len(functions_opcode)):
            [function_id_byte, function_type_byte, return_type_bytes, list_para_type_bytes, list_opc_bytes] = \
                details_from_opcode(functions_opcode[i])
            function_hex = convert_bytes_to_hex(function_id_byte)
            if i == 0:
                prefix = "0"
            else:
                prefix = "1"
            function_type_key = prefix + "{:02d}".format(
                int(function_type_byte.hex(), 16))
            function_type = meta.function_type_map[function_type_key]
            function_hex.append(function_type_byte.hex())
            if len(list_para_type_bytes) > 0:
                list_para_type = [
                    meta.data_type_list[para]
                    for para in convert_bytes_to_hex(list_para_type_bytes)
                ]
                function_hex.append([
                    para for para in convert_bytes_to_hex(list_para_type_bytes)
                ])
            else:
                list_para_type = []
                function_hex.append([])
            list_opc = [
                convert_bytes_to_hex(list_opc_line)
                for list_opc_line in list_opc_bytes
            ]

            if len(return_type_bytes) > 0:
                function_hex.append(
                    [para for para in convert_bytes_to_hex(return_type_bytes)])
            else:
                function_hex.append([])
            print_a_function(function_type, function_hex, functions_spec[i],
                             list_para_type, list_opc, all_info[2])
Exemple #15
0
 def check_with_other_node(self,
                           node_host,
                           super_node_num=DEFAULT_SUPER_NODE_NUM):
     if is_offline():
         pyvsystems.throw_error("Cannot check height in offline mode.",
                                NetworkException)
         return False
     try:
         h1 = self.height()
     except NetworkException:
         logging.error("Fail to connect {}.".format(node_host))
         return False
     try:
         other_api = Wrapper(node_host)
         h2 = other_api.request('/blocks/height')['height']
     except NetworkException:
         logging.error("Fail to connect {}.".format(node_host))
         return False
     # Add more check if need
     return h2 - h1 <= super_node_num
Exemple #16
0
 def __init__(self, data, data_type):
     if not type(data_type) is bytes:
         msg = 'Data Type must be bytes'
         pyvsystems.throw_error(msg, InvalidParameterException)
     if not check_data_type(data, data_type):
         msg = 'Invalid DataEntry'
         pyvsystems.throw_error(msg, InvalidParameterException)
     if data_type == Type.public_key:
         self.data_bytes = base58.b58decode(data)
         self.data_type = 'public_key'
     elif data_type == Type.address:
         self.data_bytes = base58.b58decode(data)
         self.data_type = 'address'
     elif data_type == Type.amount:
         self.data_bytes = struct.pack(">Q", data)
         self.data_type = 'amount'
     elif data_type == Type.int32:
         self.data_bytes = struct.pack(">I", data)
         self.data_type = 'int32'
     elif data_type == Type.short_text:
         self.data_bytes = serialize_array(str2bytes(data))
         self.data_type = 'short_text'
     elif data_type == Type.contract_account:
         self.data_bytes = base58.b58decode(data)
         self.data_type = 'contract_account'
     else:
         msg = 'Invalid Data Entry'
         pyvsystems.throw_error(msg, InvalidParameterException)
     self.data = data
     self.bytes = data_type + self.data_bytes
Exemple #17
0
 def lease_cancel(self,
                  lease_id,
                  tx_fee=DEFAULT_CANCEL_LEASE_FEE,
                  fee_scale=DEFAULT_FEE_SCALE,
                  timestamp=0):
     decode_lease_id = base58.b58decode(lease_id)
     if not self.privateKey:
         msg = 'Private key required'
         pyvsystems.throw_error(msg, MissingPrivateKeyException)
     elif tx_fee < DEFAULT_CANCEL_LEASE_FEE:
         msg = 'Transaction fee must be > %d' % DEFAULT_CANCEL_LEASE_FEE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif len(decode_lease_id) != LEASE_TX_ID_BYTES:
         msg = 'Invalid lease transaction id'
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif CHECK_FEE_SCALE and fee_scale != DEFAULT_FEE_SCALE:
         msg = 'Wrong fee scale (currently, fee scale must be %d).' % DEFAULT_FEE_SCALE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif not is_offline() and self.balance() < tx_fee:
         msg = 'Insufficient VSYS balance'
         pyvsystems.throw_error(msg, InsufficientBalanceException)
     else:
         if timestamp == 0:
             timestamp = int(time.time() * 1000000000)
         sData = struct.pack(">B", LEASE_CANCEL_TX_TYPE) + \
                 struct.pack(">Q", tx_fee) + \
                 struct.pack(">H", fee_scale) + \
                 struct.pack(">Q", timestamp) + \
                 decode_lease_id
         signature = bytes2str(sign(self.privateKey, sData))
         data = json.dumps({
             "senderPublicKey": self.publicKey,
             "txId": lease_id,
             "fee": tx_fee,
             "feeScale": fee_scale,
             "timestamp": timestamp,
             "signature": signature
         })
         req = self.wrapper.request('/leasing/broadcast/cancel', data)
         return req
Exemple #18
0
def create_data(list_data_tuple):
    custom_data = []
    if not type(list_data_tuple) is list:
        list_data_tuple = [list_data_tuple]
    for data in list_data_tuple:
        if type(data) == tuple:
            if data[1] == 'public_key' and type(data[0]) == str:
                custom_data.append(DataEntry(data[0], bytes([1])))
            if data[1] == 'address' and type(data[0]) == str:
                custom_data.append(DataEntry(data[0], bytes([2])))
            if data[1] == 'amount' and type(data[0]) == int:
                custom_data.append(DataEntry(data[0], bytes([3])))
            if data[1] == 'int32' and type(data[0]) == int:
                custom_data.append(DataEntry(data[0], bytes([4])))
            if data[1] == 'short_text' and type(data[0]) == str:
                custom_data.append(DataEntry(data[0], bytes([5])))
            if data[1] == 'contract_account' and type(data[0]) == str:
                custom_data.append(DataEntry(data[0], bytes([6])))
        else:
            msg = 'Invalid Data Entry'
            pyvsystems.throw_error(msg, InvalidParameterException)
    return custom_data
Exemple #19
0
def data_entry_from_bytes(bytes_object):
    if len(bytes_object) == 0:
        msg = 'Invalid Data Entry'
        pyvsystems.throw_error(msg, InvalidParameterException)
    elif not type(bytes_object) is bytes:
        msg = 'Input must be bytes'
        pyvsystems.throw_error(msg, InvalidParameterException)
    elif bytes_object[0:1] == Type.public_key:
        return DataEntry(bytes2str(base58.b58encode(bytes_object[1:])),
                         bytes_object[0:1])
    elif bytes_object[0:1] == Type.address:
        return DataEntry(bytes2str(base58.b58encode(bytes_object[1:])),
                         bytes_object[0:1])
    elif bytes_object[0:1] == Type.amount:
        return DataEntry(
            struct.unpack(">Q", bytes_object[1:])[0], bytes_object[0:1])
    elif bytes_object[0:1] == Type.int32:
        return DataEntry(
            struct.unpack(">I", bytes_object[1:])[0], bytes_object[0:1])
    elif bytes_object[0:1] == Type.short_text:
        return DataEntry(bytes2str(bytes_object[3:]), bytes_object[0:1])
    elif bytes_object[0:1] == Type.contract_account:
        return DataEntry(bytes2str(base58.b58encode(bytes_object[1:])),
                         bytes_object[0:1])
Exemple #20
0
 def get_tx_history(self, limit=100, type_filter=PAYMENT_TX_TYPE):
     if is_offline():
         pyvsystems.throw_error("Cannot check history in offline mode.", NetworkException)
         return []
     if not self.address:
         msg = 'Address required'
         pyvsystems.throw_error(msg, MissingAddressException)
     elif limit > MAX_TX_HISTORY_LIMIT:
         msg = 'Too big sequences requested (Max limitation is %d).' % MAX_TX_HISTORY_LIMIT
         pyvsystems.throw_error(msg, InvalidParameterException)
     else:
         url = '/transactions/address/{}/limit/{}'.format(self.address, limit)
         resp = self.wrapper.request(url)
         if isinstance(resp, list) and type_filter:
             resp = [tx for tx in resp[0] if tx['type'] == type_filter]
         return resp
Exemple #21
0
 def get_info(self):
     if not (self.address and self.publicKey):
         msg = 'Address required'
         pyvsystems.throw_error(msg, MissingAddressException)
         return None
     if not self.publicKey:
         msg = 'Public key and address required'
         pyvsystems.throw_error(msg, MissingPublicKeyException)
         return None
     if is_offline():
         info = {"publicKey": self.publicKey, "address": self.address}
         return info
     info = self.balance_detail()
     if not info:
         msg = 'Failed to get balance detail'
         pyvsystems.throw_error(msg, NetworkException)
     else:
         info["publicKey"] = self.publicKey
         return info
Exemple #22
0
 def lease(self, recipient, amount, tx_fee=DEFAULT_LEASE_FEE, fee_scale=DEFAULT_FEE_SCALE, timestamp=0):
     if not self.privateKey:
         msg = 'Private key required'
         pyvsystems.throw_error(msg, MissingPrivateKeyException)
     if not self.chain.validate_address(recipient.address):
         msg = 'Invalid recipient address'
         pyvsystems.throw_error(msg, InvalidAddressException)
     elif amount <= 0:
         msg = 'Amount must be > 0'
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif tx_fee < DEFAULT_LEASE_FEE:
         msg = 'Transaction fee must be >= %d' % DEFAULT_LEASE_FEE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif CHECK_FEE_SCALE and fee_scale != DEFAULT_FEE_SCALE:
         msg = 'Wrong fee scale (currently, fee scale must be %d).' % DEFAULT_FEE_SCALE
         pyvsystems.throw_error(msg, InvalidParameterException)
     elif not is_offline() and self.balance() < amount + tx_fee:
         msg = 'Insufficient VSYS balance'
         pyvsystems.throw_error(msg, InsufficientBalanceException)
     else:
         if timestamp == 0:
             timestamp = int(time.time() * 1000000000)
         sData = struct.pack(">B", LEASE_TX_TYPE) + \
                 base58.b58decode(recipient.address) + \
                 struct.pack(">Q", amount) + \
                 struct.pack(">Q", tx_fee) + \
                 struct.pack(">H", fee_scale) + \
                 struct.pack(">Q", timestamp)
         signature = bytes2str(sign(self.privateKey, sData))
         data = json.dumps({
             "senderPublicKey": self.publicKey,
             "recipient": recipient.address,
             "amount": amount,
             "fee": tx_fee,
             "feeScale": fee_scale,
             "timestamp": timestamp,
             "signature": signature
         })
         req = self.wrapper.request('/leasing/broadcast/lease', data)
         return req
Exemple #23
0
 def check_is_offline():
     if is_offline():
         pyvsystems.throw_error("Cannot check transaction in offline mode.",
                                NetworkException)
def print_a_function(function_type, function_hex, functions_spec,
                     list_para_type, list_opc, all_state_var):
    return_type = functions_spec[1]
    function_name = functions_spec[2]
    para_name = functions_spec[3]
    state_var = all_state_var[0]
    if len(list_para_type) >= 1:
        list_para = para_name[:len(list_para_type)]
    else:
        list_para = []
    if len(list_para_type) != len(list_para):
        msg = 'List of parameter is not right!'
        pyvsystems.throw_error(msg, InvalidParameterException)
    else:
        if function_type == meta.function_type_map['000']:
            prefix = "trigger"
            if shorts_from_byte_array(function_hex[0:2]) == 0:
                print("Triggers: ")
        else:
            prefix = "function"
            if shorts_from_byte_array(function_hex[0:2]) == 0:
                print("Descriptor Functions: ")
        print(function_type + ' ' + prefix + ' ' + function_name + "(", end='')
        if len(list_para_type) > 0:
            for i in range(len(list_para_type)):
                print(list_para_type[i] + ' ', end='')
                if i == (len(list_para_type) - 1):
                    print(list_para[i] + ') ', end='')
                else:
                    print(list_para[i] + ', ', end='')
        else:
            print(') ', end='')

    if function_hex[4]:
        for i in range(len(return_type)):
            print('return ' + meta.data_type_list[function_hex[4][i]] + ' ' +
                  return_type[0])
    else:
        print(' ')

    print("| " + ' '.join(function_hex[0:2]) + " | " + function_hex[2] + " ",
          end='')
    if function_hex[3]:
        print("| " + ' '.join(function_hex[3]) + " ", end='')
    else:
        print("| - ", end='')
    if function_hex[4]:
        print("| " + ' '.join(function_hex[4]) + " ", end='')
    else:
        print("| - ", end='')
    print("| ")
    list_opc_name = [
        Opcode().function_name[opc[0] + opc[1]]
        if len(opc) >= 2 else pyvsystems.throw_error(
            'Opc function is not right!', InvalidParameterException)
        for opc in list_opc
    ]
    if len(list_opc_name) != len(list_opc):
        msg = 'Opc function is not right!'
        pyvsystems.throw_error(msg, InvalidParameterException)
    else:
        name_list = copy.deepcopy(para_name)
        for i in range(len(list_opc_name)):
            data = copy.deepcopy([int(index) for index in list_opc[i]])
            print(' ' * 13, end='')
            Opcode().get_opc(list_opc_name[i], [data, name_list, state_var])
            print(' ' * 13, end='')
            print('| ' + list_opc[i][0] + ' ' + list_opc[i][1] + ' | ' +
                  ' '.join(list_opc[i][2:]) + ' |')
        print(" ")
Exemple #25
0
    def dbput(self, db_key, db_data, db_data_type="ByteArray", tx_fee=DEFAULT_DBPUT_FEE, fee_scale=DEFAULT_FEE_SCALE, timestamp=0):
        if not self.privateKey:
            msg = 'Private key required'
            pyvsystems.throw_error(msg, MissingPrivateKeyException)
        elif tx_fee < DEFAULT_DBPUT_FEE:
            msg = 'Transaction fee must be >= %d' % DEFAULT_DBPUT_FEE
            pyvsystems.throw_error(msg, InvalidParameterException)
        elif len(db_key) > MAX_DB_KEY_SIZE or len(db_key) < MIN_DB_KEY_SIZE:
            msg = 'DB key length must be greater than %d and smaller than %d' % (MIN_DB_KEY_SIZE, MAX_ATTACHMENT_SIZE)
            pyvsystems.throw_error(msg, InvalidParameterException)
        elif CHECK_FEE_SCALE and fee_scale != DEFAULT_FEE_SCALE:
            msg = 'Wrong fee scale (currently, fee scale must be %d).' % DEFAULT_FEE_SCALE
            pyvsystems.throw_error(msg, InvalidParameterException)
        elif not is_offline() and self.balance() < tx_fee:
            msg = 'Insufficient VSYS balance'
            pyvsystems.throw_error(msg, InsufficientBalanceException)
        else:
            if timestamp == 0:
                timestamp = int(time.time() * 1000000000)
            # "ByteArray" is the only supported type in first version
            if db_data_type == "ByteArray":
                data_type_id = b'\x01'
            # TODO: add more DB data type here
            else:
                msg = 'Unsupported data type: {}'.format(db_data_type)
                pyvsystems.throw_error(msg, InvalidParameterException)
                return
            sData = struct.pack(">B", DBPUT_TX_TYPE) + \
                    struct.pack(">H", len(db_key)) + \
                    str2bytes(db_key) + \
                    struct.pack(">H", len(db_data)+1) + \
                    data_type_id + \
                    str2bytes(db_data) + \
                    struct.pack(">Q", tx_fee) + \
                    struct.pack(">H", fee_scale) + \
                    struct.pack(">Q", timestamp)
            signature = bytes2str(sign(self.privateKey, sData))
            data = json.dumps({
                  "senderPublicKey": self.publicKey,
                  "dbKey": db_key,
                  "dataType": db_data_type,
                  "data": db_data,
                  "fee": tx_fee,
                  "feeScale": fee_scale,
                  "timestamp": timestamp,
                  "signature": signature
            })

            return self.wrapper.request('/database/broadcast/put', data)