Example #1
0
class PlatonContractTransaction:
    """
    合约创建参数list结构:[txType,byteCode,abi]
    合约调用参数list结构:[txType,funcName,params01,params02,...]
    """
    def __init__(self, URL):
        # test address 'http://10.10.8.20:8545'
        self.w3 = Web3(Web3.HTTPProvider(URL))
        self.eth = Eth(self.w3)
        self.personal = Personal(self.w3)
        print("if the web3 isConnected : {}".format(self.w3.isConnected()))

    def get_signed_data(self, fromAddress, toAddress, dataList, privateKey):
        myNonce = self.eth.getTransactionCount(fromAddress)
        data = rlp.encode(dataList)
        transactionDict = {
            "from": fromAddress,
            "to": toAddress,
            "gasPrice": "0x8250de00",
            "gas": "0x1fffff",  # rule of thumb / guess work
            "nonce": myNonce,
            "data": data,
        }
        signedTransactionDict = self.eth.account.signTransaction(
            transactionDict, privateKey)
        return signedTransactionDict.rawTransaction

    def contract_deploy(self, txType, bytecode, abi, fromAddress):
        """
        非签名合约部署
        :param txType:取值类型 0-主币转账交易 1-合约发布 2-合约调用 3-投票 4-权限
        :param bytecode:合约bin(wasm文件),二进制数组
        :param abi:abi(json文件),二进制数组
        :param fromAddress:钱包地址
        :return:合约部署transactionHash
        """
        txType = platon_encoder.encode_type(txType)
        bytecode = bytecode
        abi = abi
        rlpList = [txType, bytecode, abi]
        data = rlp.encode(rlpList)
        transactionHash = self.eth.sendTransaction({
            "from": fromAddress,
            "gas": "0x1fffff",
            "gasPrice": "0x8250de00",
            "data": data,
        })
        transactionHash = HexBytes(transactionHash).hex().lower()
        print(transactionHash)
        return transactionHash

    def contract_transaction(self, fromAddress, contractAddress, dataList):
        """
        非签名合约交易
        :param fromAddress: 钱包地址
        :param contractAddress: 合约地址
        :param dataList: 参数list
        :return:合约交易transactionHash
        """
        data = rlp.encode(dataList)
        transactionHash = self.eth.sendTransaction({
            "from": fromAddress,
            "to": contractAddress,
            "gas": "0x1fffff",
            "gasPrice": "0x8250de00",
            "data": data,
        })
        transactionHash = HexBytes(transactionHash).hex().lower()
        print(transactionHash)
        return transactionHash

    def contract_call(self, fromAddress, contractAddress, dataList):
        """
        合约查询交易
        :param fromAddress:钱包地址
        :param contractAddress:合约地址
        :param dataList:参数list
        :return:
        """
        data = rlp.encode(dataList)
        recive = self.eth.call({
            "from": fromAddress,
            "to": contractAddress,
            "data": data
        })
        # recive = HexBytes(recive).decode()
        print(recive)
        return recive

    def signed_contract_deploy(self, txType, bytecode, abi, fromAddress,
                               privateKey):
        """
        签名部署合约
        :param txType:取值类型 0-主币转账交易 1-合约发布 2-合约调用 3-投票 4-权限
        :param bytecode:bytecode,二进制数组
        :param abi:abi,二进制数组
        :param fromAddress:钱包地址
        :param privateKey:钱包私钥
        :return:transactionHash
        """
        txType = platon_encoder.encode_type(txType)
        bytecode = bytecode
        abi = abi
        rlpList = [txType, bytecode, abi]
        signedData = self.get_signed_data(rlpList, fromAddress, "", privateKey)
        transactionHash = self.eth.sendRawTransaction(signedData)
        transactionHash = HexBytes(transactionHash).hex().lower()
        print(transactionHash)
        return transactionHash

    def signed_contract_transaction(self, fromAddress, contractAddress,
                                    dataList, privateKey):
        """
        签名合约交易
        :param fromAddress:钱包地址
        :param contractAddress:合约地址
        :param dataList:参数list
        :param privateKey:钱包私钥
        :return:transactionHash
        """
        signedData = self.get_signed_data(fromAddress, contractAddress,
                                          dataList, privateKey)
        transactionHash = self.eth.sendRawTransaction(signedData)
        transactionHash = HexBytes(transactionHash).hex().lower()
        print(transactionHash)
        return transactionHash
Example #2
0
class PlatonDpos:
    def __init__(self,
                 url,
                 address,
                 pwd,
                 abi=r"./data/dpos/candidateConstract.json",
                 vote_abi=r'./data/dpos/ticketContract.json',
                 privatekey=conf.PRIVATE_KEY):
        self.web3 = connect_web3(url)
        if not self.web3.isConnected():
            raise Exception("节点连接失败")
        self.eth = Eth(self.web3)
        self.address = address
        self.abi = abi
        self.vote_abi = vote_abi
        self.value = 100
        self.privatekey = privatekey

    def get_result(self, tx_hash, func_name, abi=None):
        result = self.eth.waitForTransactionReceipt(tx_hash)
        """查看eventData"""
        topics = result['logs'][0]['topics']
        data = result['logs'][0]['data']
        if abi is None:
            event = Event(json.load(open(self.abi)))
        else:
            event = Event(json.load(open(abi)))
        event_data = event.event_data(topics, data)
        return event_data, func_name

    def send_raw_transaction(self, data, from_address, to_address, value):
        nonce = self.eth.getTransactionCount(from_address)
        if value > 0:
            transaction_dict = {
                "to": to_address,
                "gasPrice": "0x8250de00",
                "gas": "0x6fffffff",
                "nonce": nonce,
                "data": data,
                "value": self.web3.toWei(value, "ether"),
            }
        else:
            transaction_dict = {
                "to": to_address,
                "gasPrice": "0x8250de00",
                "gas": "0x6fffffff",
                "nonce": nonce,
                "data": data,
            }
        signedTransactionDict = self.eth.account.signTransaction(
            transaction_dict, self.privatekey)
        data = signedTransactionDict.rawTransaction
        result = HexBytes(self.eth.sendRawTransaction(data)).hex()
        return result

    def CandidateDeposit(self,
                         nodeid,
                         owner,
                         fee,
                         host,
                         port,
                         extra,
                         value=None):
        '''
        @Description: 节点候选人申请/增加质押,质押金额为交易的value值。
        @param
            nodeId: [64]byte 节点ID(公钥)
            owner: [20]byte 质押金退款地址
            fee: uint32 出块奖励佣金比,以10000为基数(eg:5%,则fee=500)
            host: string 节点IP
            port: string 节点P2P端口号
            Extra: string 附加数据(有长度限制,限制值待定)
        @return:
            出参(事件:CandidateDepositEvent):
            Ret: bool 操作结果
            ErrMsg: string 错误信息
        '''
        data = rlp.encode([
            int(1001).to_bytes(8, 'big'), self.CandidateDeposit.__name__,
            nodeid, owner, fee, host,
            str(port), extra
        ])
        if not value:
            value = self.value
        to = "0x1000000000000000000000000000000000000001"
        result = self.send_raw_transaction(data, self.address, to, value)
        # print('!!!!!', result)
        return self.get_result(result, self.CandidateDeposit.__name__)

    def CandidateApplyWithdraw(self, nodeid, withdraw):
        '''
        @Description: 节点质押金退回申请,申请成功后节点将被重新排序,权限校验from==owner
        @param
            nodeId: [64]byte 节点ID(公钥)
            withdraw: uint256 退款金额 (单位:ADP)
        @return:
            出参(事件:CandidateApplyWithdrawEvent):
            Ret: bool 操作结果
            ErrMsg: string 错误信息
        '''
        # withdraw = np.uint256(withdraw)
        data = rlp.encode([
            int(1002).to_bytes(8, 'big'), self.CandidateApplyWithdraw.__name__,
            nodeid,
            self.web3.toWei(withdraw, 'ether')
        ])
        to = "0x1000000000000000000000000000000000000001"
        result = self.send_raw_transaction(data, self.address, to, value=0)
        # print('申请退回hx:', result)
        return self.get_result(result, self.CandidateApplyWithdraw.__name__)

    def GetCandidateWithdrawInfos(self, nodeid):
        '''
        @Description: 获取节点申请的退款记录列表
        @param {type}
            nodeId: [64]byte 节点ID(公钥)
        @return:
            Ret: bool 操作结果
            ErrMsg: string 错误信息
            []:列表
            'Balance': uint256 退款金额 (单位:ADP)
            LockNumber: uint256 退款申请所在块高
            LockBlockCycle: uint256 退款金额锁定周期
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'),
            self.GetCandidateWithdrawInfos.__name__, nodeid
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000001",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile(r'{.*}')
        recive = re.findall(p, recive)[0]
        recive = json.loads(recive)
        return recive

    def CandidateWithdraw(self, nodeid):
        '''
        @Description: 节点质押金提取,调用成功后会提取所有已申请退回的质押金到owner账户。
        @param:
            nodeId: [64]byte 节点ID(公钥)
        @return:
            出参(事件:CandidateWithdrawEvent):
            Ret: bool 操作结果
            ErrMsg: string 错误信息
        '''
        data = HexBytes(
            rlp.encode([
                int(1003).to_bytes(8, 'big'), self.CandidateWithdraw.__name__,
                nodeid
            ])).hex()
        to = "0x1000000000000000000000000000000000000001"
        result = self.send_raw_transaction(data, self.address, to, value=0)
        # print('退回hx:', result)
        return self.get_result(result, self.CandidateWithdraw.__name__)

    def SetCandidateExtra(self):
        '''
        @Description: 设置节点附加信息,供前端扩展使用
        @param:
            nodeId: [64]byte 节点ID(公钥)
            extra: string 附加信息
        @return:
            出参(事件:SetCandidateExtraEvent):
            Ret: bool 操作结果
            ErrMsg: string 错误信息
        '''
        pass

    def GetCandidateDetails(self, nodeid):
        '''
        @Description: 获取候选人信息。
        @param {type} nodeId: [64]byte 节点ID(公钥)
        @return:
            Deposit: uint256 质押金额 (单位:ADP)
            BlockNumber: uint256 质押金更新的最新块高
            Owner: [20]byte 质押金退款地址
            TxIndex: uint32 所在区块交易索引
            CandidateId: [64]byte 节点Id(公钥)
            From: [20]byte 最新质押交易的发送方
            Fee: uint64 出块奖励佣金比,以10000为基数(eg:5%,则fee=500)
            Host: string 节点IP
            Port: string 节点P2P端口号
            Extra: string 附加数据(有长度限制,限制值待定)
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'), self.GetCandidateDetails.__name__,
            nodeid
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000001",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile(r'{.*}')
        recive = re.findall(p, recive)[0]
        recive = re.sub("{{", "{", recive)
        recive = json.loads(recive)
        return recive

    def GetCandidateList(self):
        '''
        @Description: 获取所有入围节点的信息列表
        @param {type} @@@@
        @return:
            Ret: bool 操作结果
            ErrMsg: string 错误信息
            []:列表
            Deposit: uint256 质押金额 (单位:ADP)
            BlockNumber: uint256 质押金更新的最新块高
            Owner: [20]byte 质押金退款地址
            TxIndex: uint32 所在区块交易索引
            CandidateId: [64]byte 节点Id(公钥)
            From: [20]byte 最新质押交易的发送方
            Fee: uint64 出块奖励佣金比,以10000为基数(eg:5%,则fee=500)
            Host: string 节点IP
            Port: string 节点P2P端口号
            Extra: string 附加数据(有长度限制,限制值待定)
        '''
        data = rlp.encode(
            [int(10).to_bytes(8, 'big'), self.GetCandidateList.__name__])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000001",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        recive = re.sub("{\[", "[", recive)
        p = re.compile(r'{.*?}')
        recive = re.findall(p, recive)
        try:
            recive = [json.loads(i) for i in recive]
        except Exception as e:
            raise e
        return recive

    def GetVerifiersList(self):
        '''
        @Description: 获取参与当前共识的验证人列表
        @param {type} @@@@
        @return:
            Ret: bool 操作结果
            ErrMsg: string 错误信息
            []:列表
            Deposit: uint256 质押金额 (单位:ADP)
            BlockNumber: uint256 质押金更新的最新块高
            Owner: [20]byte 质押金退款地址
            TxIndex: uint32 所在区块交易索引
            CandidateId: [64]byte 节点Id(公钥)
            From: [20]byte 最新质押交易的发送方
            Fee: uint64 出块奖励佣金比,以10000为基数(eg:5%,则fee=500)
            Host: string 节点IP
            Port: string 节点P2P端口号
            Extra: string 附加数据(有长度限制,限制值待定)
        '''
        data = rlp.encode(
            [int(10).to_bytes(8, 'big'), self.GetVerifiersList.__name__])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000001",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile(r'{.*?}')
        recive = re.findall(p, recive)
        recive = [json.loads(i) for i in recive]
        return recive

    def VoteTicket(self, count, price, nodeid, voter, value=None):
        '''
        购买选票,投票给候选人
        :param count: uint64 购票数量
        :param price:*big.Int 选票单价
        :param nodeid:[64]byte 候选人节点Id
        :param value: 发送交易的value为  购票数量 * 选票单价
        :return:
            出参(事件:VoteTicketEvent):
            Ret: bool  操作结果
            Data: string  返回数据(成功选票的数量)
            ErrMsg: string  错误信息
        '''
        data = rlp.encode([
            int(1000).to_bytes(8, 'big'), self.VoteTicket.__name__,
            int(count).to_bytes(4, 'big'),
            int(self.web3.toWei(price, 'ether')).to_bytes(8, 'big'), nodeid
        ])
        if not value:
            value = self.value
        to = "0x1000000000000000000000000000000000000002"
        result_hex = self.send_raw_transaction(data, voter, to, value)
        result, _ = self.get_result(result_hex,
                                    self.VoteTicket.__name__,
                                    abi=self.vote_abi)
        return result, result_hex

    def GetTicketPrice(self):
        '''
        获取当前的票价
        :return:
            ret: *big.Int 当前票价
            error: string  错误信息
        '''
        data = rlp.encode(
            [int(10).to_bytes(8, 'big'), self.GetTicketPrice.__name__])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = HexBytes(recive).decode('utf-8')
        partern = re.compile(r'\d')
        recive = ''.join(re.findall(partern, recive))
        return int(recive)

    def GetCandidateTicketIds(self, nodeid):
        '''
        获取指定候选人的选票Id的列表
        :param nodeid: [64]byte 节点Id
        :return:
            ret: []ticketId 选票的Id列表
            error: string 错误信息
        '''
        data = HexBytes(
            rlp.encode([
                int(10).to_bytes(8, 'big'),
                self.GetCandidateTicketIds.__name__, nodeid
            ])).hex()
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile('\"(.+?)\"')
        recive = re.findall(p, recive)
        return recive

    def GetBatchCandidateTicketIds(self, node_ids):
        '''
        批量获取指定候选人的选票Id的列表
        :param node_ids: []nodeId 节点Id列表
        :return:
            ret: []ticketIds 多个节点的选票的Id列表
            error: string 错误信息
        '''
        encode_list = [
            int(10).to_bytes(8, 'big'),
            self.GetBatchCandidateTicketIds.__name__, ':'.join(node_ids)
        ]
        data = rlp.encode(encode_list)
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile(r"{.*?}")
        recive = re.findall(p, recive)
        recive = [json.loads(i) for i in recive]
        return recive

    def GetTicketDetail(self, ticket_id):
        '''
        获取票详情
        :param ticket_id:[32]byte 票Id
        :return:
            ret: Ticket 选票信息
            error: string 错误信息
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'), self.GetTicketDetail.__name__,
            ticket_id
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile(r"{.*?}")
        recive = re.findall(p, recive)
        recive = [json.loads(i) for i in recive]
        return recive

    def GetBatchTicketDetail(self, ticket_ids):
        '''
        批量获取票详情
        :param ticket_ids:[]ticketId 票Id列表
        :return:
            ret: []Ticket 选票信息列表
            error: string 错误信息
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'), self.GetBatchTicketDetail.__name__,
            ':'.join(ticket_ids)
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        p = re.compile(r"{.*?}")
        recive = re.findall(p, recive)
        recive = [json.loads(i) for i in recive]
        return recive

    def GetCandidateEpoch(self, nodeid):
        '''
        获取指定候选人的票龄
        :param nodeid:[64]byte 节点Id
        :return:
            ret: uint64 票龄
            error: string 错误信息
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'), self.GetCandidateEpoch.__name__, nodeid
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        partern = re.compile(r'\d')
        recive = ''.join(re.findall(partern, recive))
        return int(recive)

    def GetTicketCountByTxHash(self, txHashs):
        '''
        (批量)获取交易的有效选票数量
        :param txHashs: string 多个txHashs通过":"拼接的字符串
        :return:
            ret: dict(nodeId)uint32 多个节点的有效选票数量
            error: string 错误信息
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'), self.GetTicketCountByTxHash.__name__,
            txHashs
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        partern = re.compile(r'{.+?}')
        recive = re.findall(partern, recive)[0]
        recive = eval(recive)
        return recive

    def GetCandidateTicketCount(self, nodeIds):
        '''
        (批量)获取指定候选人的有效选票数量
        :param nodeIds: string 多个nodeId通过":"拼接的字符串
        :return:
            ret: dict(txHash)uint32 多个交易的有效选票数量
            error: string 错误信息
        '''
        data = rlp.encode([
            int(10).to_bytes(8, 'big'), self.GetCandidateTicketCount.__name__,
            nodeIds
        ])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        partern = re.compile(r'{.+?}')
        recive = re.findall(partern, recive)[0]
        recive = eval(recive)
        return recive

    def GetPoolRemainder(self):
        '''
        获取票池剩余票数量
        :return:
            ret: uint64 剩余票数量
            error: string 错误信息
        '''
        data = rlp.encode(
            [int(10).to_bytes(8, 'big'), self.GetPoolRemainder.__name__])
        recive = self.eth.call({
            "from": self.address,
            "to": "0x1000000000000000000000000000000000000002",
            "data": data
        })
        recive = str(recive, encoding="ISO-8859-1")
        partern = re.compile(r'\d')
        recive = ''.join(re.findall(partern, recive))
        return int(recive)
Example #3
0
class PlatonContractTransaction:
    """
    合约创建参数list结构:[txType,byteCode,abi]
    合约调用参数list结构:[txType,funcName,params01,params02,...]
    """
    def __init__(self, URL):
        self.URL = URL
        self.w3 = connect_web3(URL)
        self.eth = Eth(self.w3)
        self.personal = Personal(self.w3)
        for i in range(5):
            if self.w3.isConnected():
                break
            else:
                self.w3 = connect_web3(URL)
            time.sleep(1)
        else:
            raise Exception("节点连接失败")

    def reconnect(self):
        self.w3 = connect_web3(self.URL)
        self.eth = Eth(self.w3)
        self.personal = Personal(self.w3)

    def get_signed_data(self, fromAddress, toAddress, dataList, privateKey):
        myNonce = self.eth.getTransactionCount(fromAddress)
        data = rlp.encode(dataList)
        transactionDict = {
            "from": fromAddress,
            "to": toAddress,
            "gasPrice": "0x8250de00",
            "gas": "0x6fffffff",  # rule of thumb / guess work
            "nonce": myNonce,
            "data": data,
        }
        signedTransactionDict = self.eth.account.signTransaction(
            transactionDict, privateKey)
        return signedTransactionDict.rawTransaction

    def contract_deploy(self, bytecode, abi, fromAddress):
        """
        非签名合约部署
        :param txType:取值类型 0-主币转账交易 1-合约发布 2-合约调用 3-投票 4-权限
        :param bytecode:合约bin(wasm文件),二进制数组
        :param abi:abi(json文件),二进制数组
        :param fromAddress:钱包地址
        :return:合约部署transactionHash
        """
        txType = encoder.encode_type(1)
        bytecode = bytecode
        abi = abi
        rlpList = [txType, bytecode, abi]
        data = rlp.encode(rlpList)
        transactionHash = self.eth.sendTransaction({
            "from": fromAddress,
            "gas": "0x6fffffff",
            "gasPrice": "0x8250de00",
            "data": data,
        })
        transactionHash = HexBytes(transactionHash).hex().lower()
        return transactionHash

    def contract_transaction(self, fromAddress, contractAddress, dataList):
        """
        非签名合约交易
        :param fromAddress: 钱包地址
        :param contractAddress: 合约地址
        :param dataList: 参数list
        :return:合约交易transactionHash
        """
        data = rlp.encode(dataList)
        transactionHash = self.eth.sendTransaction({
            "from": fromAddress,
            "to": contractAddress,
            "gas": "0x6fffffff",
            "gasPrice": "0x8250de00",
            "data": data,
        })
        transactionHash = HexBytes(transactionHash).hex().lower()
        return transactionHash

    def contract_call(self, fromAddress, contractAddress, dataList):
        """
        合约查询交易
        :param fromAddress:钱包地址
        :param contractAddress:合约地址
        :param dataList:参数list
        :return:
        """
        data = rlp.encode(dataList)
        recive = self.eth.call({
            "from": fromAddress,
            "to": contractAddress,
            "data": data
        })
        return recive

    def signed_contract_deploy(self, bytecode, abi, fromAddress, privateKey):
        """
        签名部署合约
        :param txType:取值类型 0-主币转账交易 1-合约发布 2-合约调用 3-投票 4-权限
        :param bytecode:bytecode,二进制数组
        :param abi:abi,二进制数组
        :param fromAddress:钱包地址
        :param privateKey:钱包私钥
        :return:transactionHash
        """
        txType = encoder.encode_type(1)
        bytecode = bytecode
        abi = abi
        rlpList = [txType, bytecode, abi]
        signedData = self.get_signed_data(fromAddress, "", rlpList, privateKey)
        transactionHash = self.eth.sendRawTransaction(signedData)
        transactionHash = HexBytes(transactionHash).hex().lower()
        return transactionHash

    def signed_contract_transaction(self, fromAddress, contractAddress,
                                    dataList, privateKey):
        """
        签名合约交易
        :param fromAddress:钱包地址
        :param contractAddress:合约地址
        :param dataList:参数list
        :param privateKey:钱包私钥
        :return:transactionHash
        """
        signedData = self.get_signed_data(fromAddress, contractAddress,
                                          dataList, privateKey)
        transactionHash = self.eth.sendRawTransaction(signedData)
        transactionHash = HexBytes(transactionHash).hex().lower()
        return transactionHash

    def contract_call_string(self, fromAddress, contractAddress, dataList):
        result = self.contract_call(fromAddress, contractAddress, dataList)
        length = int(result[66:130], 16) * 2
        data = result[130:130 + length]
        ret = HexBytes(data).decode()
        return ret.lower()