Exemple #1
0
class Web3Service:
    def __init__(self, http_endpoint):
        self.w3 = Web3(Web3.HTTPProvider(http_endpoint))
        self.eth = Eth(self.w3)
        # self.accountPK = os.environ.get('PK')
        self.accountPBK = self.w3.toChecksumAddress(
            "0xb7e888BEa1ABAF7e999E8f66Dd826b4d046E40A5"
        )  #("0x40A5673B35dbB64CeeF457ba68Eceb29bd3f96Fb")
        print("Started web3 service")

    def sign_tx(
        self,
        contractFunc,
        options=None
    ):  # This will generate a signed tx with the private key of the service
        nonce = self.eth.getTransactionCount(self.accountPBK)
        tx = contractFunc.buildTransaction({
            'nonce':
            nonce,
            'gasPrice':
            self.w3.toWei('21', 'gwei')
        })
        pk = os.environ.get('PK')
        signedTx = self.eth.account.signTransaction(tx, private_key=pk)
        return signedTx
class ContentContract(object):
    """Content contract"""
    def __init__(
        self,
        keystore_file=None,
        keystore_pwd=None,
        private_key=None,
        provider=base_config.provider,
        gas_price=GAS_PRICE,
    ):
        """ 合约方法调用类
        参数有可能会变化, 所以调用时最好指定参数名
        :param keystore_file: user account keystore file, which include user account private key
        :param keystore_pwd: user account keystore password
        :param provider: Ulord side provider, such as http://xxxx:yyy, which is a RPC endpoint
        """
        self.web3 = Web3(HTTPProvider(provider))
        self.gas_limit = base_config.BLOCK_GAS_LIMIT
        self.gas_price = gas_price

        self.last_tx = None

        self.main_address = None
        if private_key:
            self.set_account_from_private_key(private_key)
        elif keystore_file and keystore_pwd:
            self.set_account_from_wallet(keystore_file, keystore_pwd)

        # Rinkeby 测试网络使用的是POA权威证明, 需要使用这个插件才能正常工作
        # http://web3py.readthedocs.io/en/stable/middleware.html#geth-style-proof-of-authority
        if provider.startswith("https://rinkeby"):
            self.web3.middleware_stack.inject(geth_poa_middleware, layer=0)
        self.eth = Eth(self.web3)

        # 装载所有合约
        self.reloading_contract()

    @staticmethod
    def _load_wallet(wallet_file):
        if not os.path.isfile(wallet_file):
            wallet_file = os.path.join(base_config.CURR_DIR, 'resources',
                                       'keystore', wallet_file)
            if not os.path.isfile(wallet_file):
                raise ValueError("Wallet file not a valid path.")
        with open(wallet_file) as wf:
            wallet = json.load(wf)
        return wallet

    @staticmethod
    def _save_wallet(wallet, file_name):
        wf = os.path.join(base_config.CURR_DIR, 'resources', 'keystore',
                          "{}.json".format(file_name))
        print("Wallet file address:\n{}".format(wf))
        with open(wf, "w") as f:
            json.dump(wallet, f)

    @staticmethod
    def valid_address(address):
        """验证是否是一个以太坊地址, 用EIP55校验和返回给定的地址。"""
        if not Web3.isAddress(address):
            return None
        address = Web3.toChecksumAddress(address)
        return address

    def _load_abi(self):
        abi_path = os.path.join(base_config.CURR_DIR, 'abi')
        file_list = os.listdir(abi_path)
        self.abi_files = {}
        for i in file_list:
            if not i.endswith(".abi"):
                continue
            with open(os.path.join(abi_path, i)) as cp:
                cp_abi = cp.read()
                self.abi_files[i[:-4]] = json.loads(cp_abi)

    def _nonce(self, value=0, address=None):
        if address is None:
            address = self.account.address
        nonce = self.eth.getTransactionCount(address) + value
        return nonce

    def _build_transaction(self,
                           func,
                           gas_limit=None,
                           gas_price=None,
                           nonce=None):
        """将合约方法的调用构建为离线交易对象"""
        return func.buildTransaction({
            "nonce":
            nonce if nonce else self._nonce(),
            "gas":
            gas_limit if gas_limit else self.gas_limit,
            "gasPrice":
            gas_price if gas_price else self.gas_price,
        })

    def _sign_and_send_rawtransaction(self, transaction):
        signed = self.account.signTransaction(transaction)
        tx_hash = Web3.toHex(self.eth.sendRawTransaction(
            signed.rawTransaction))
        return tx_hash

    def create(self, wallet_password):
        """创建一个账户, 保存key file到对应目录的json文件中, 且返回私钥和地址"""
        setattr(self, "account", Account.create())
        wallet = self.account.encrypt(wallet_password)
        self._save_wallet(wallet, self.account.address)
        return dict(
            privateKey=Web3.toHex(self.account.privateKey),
            address=self.account.address,
        )

    def set_account_from_private_key(self, private_key, wallet_password=None):
        """如果有钱包密码, 则创建对应的keystore文件. 反之 ,则不新建"""
        setattr(self, "account", Account.privateKeyToAccount(private_key))
        if wallet_password:
            wallet = self.account.encrypt(wallet_password)
            self._save_wallet(wallet, self.account.address)
        self.main_address = self.web3.eth.account.privateKeyToAccount(
            private_key).address

        # self.web3.eth.defaultAccount = self.web3.eth.accounts[0]
        return dict(
            privateKey=Web3.toHex(self.account.privateKey),
            address=self.account.address,
        )

    def set_account_from_wallet(self, wallet_file, wallet_password):
        """从密钥文件加载 account 对象"""
        wallet = self._load_wallet(wallet_file)
        private_key = Account.decrypt(wallet, wallet_password)
        setattr(self, "account", Account.privateKeyToAccount(private_key))
        self.main_address = self.web3.eth.account.privateKeyToAccount(
            private_key).address
        # print(self.web3.eth.defaultAccount, self.web3.eth.accounts,self.web3.eth.account)
        self.web3.eth.defaultAccount = self.web3.eth.account
        return dict(privateKey=Web3.toHex(private_key),
                    address=self.account.address)

    def get_for_receipt(self, tx_hash):
        """ 获取交易回执
        :param tx_hash: 获取交易回执(只有已打包的交易才有数据,否则返回None)
        :return:
        """
        return self.web3.eth.getTransactionReceipt(tx_hash)

    def get_gas_balance(self, address):
        """ 获取侧链余额
        """
        if address is None:
            address = self.main_address
        address = self.valid_address(address)
        balance = self.web3.eth.getBalance(address, 'latest')
        return self.web3.fromWei(balance, 'ether')

    @check_account
    def transfer_gas(self, to_address, value):
        """ gas就是侧链的币,

        :param to_address: 接收地址
        :param value: 转账金额(wei)
        :return: 交易hash
        """
        print("nonce:", self._nonce())
        to_address = self.valid_address(to_address)
        payload = {
            "to": to_address,
            "value": value,
            "gas": self.gas_limit,
            "gasPrice": self.gas_price,
            "nonce": self._nonce(),
        }
        res = self._sign_and_send_rawtransaction(payload)
        self.last_tx = res
        return res

    def transfer_tokens(self, addresses, qualitys):
        """ 多地址结算
        :param addresses: List, 结算的地址列表
        :param qualitys: List, 结算地址列表对应的金额
        """
        for i, address in enumerate(addresses):
            addresses[i] = self.valid_address(address)
        for i, quality in enumerate(qualitys):
            qualitys[i] = int(quality)
        publish_tx = self.contract["MulTransfer"].functions.mulPayDiff(
            addresses, qualitys).buildTransaction({
                "nonce": self._nonce(),
                "gas": self.gas_limit,
                "gasPrice": self.gas_price
            })
        res = self._sign_and_send_rawtransaction(publish_tx)
        self.last_tx = res
        return res

    # zza write

    def reloading_contract(self):
        try:
            # 所有合约的abi
            self._load_abi()
            # 所有合约
            self._load_contract()
        except FileNotFoundError:
            print(
                "Please use the deploy_contract command to deploy the contract first, or manually prepare the "
                "contract address。")

    def _load_contract(self):
        # 读取合约地址
        with open(os.path.join(base_config.CURR_DIR,
                               "contractAddresses.json")) as wf:
            contract_addr_list = json.load(wf)
        self.contract = {}
        # 装载合约
        for contract, addr in contract_addr_list.items():
            try:
                self.contract[contract] = self.web3.eth.contract(
                    address=self.valid_address(addr),
                    abi=self.abi_files[contract])
            except:
                continue
            view_funcs = []
            abi = {}
            for func in self.abi_files[contract]:
                if func['type'] == 'function':
                    if func.get('constant') and func.get(
                            "stateMutability") == 'view':
                        view_funcs.append(func["name"])
                    abi[func['name']] = func
            self.contract[contract].view_funcs = view_funcs
            self.contract[contract].abi = abi

    @check_account
    def func_call(self, contract_name, function, param):
        # 找到合约中对应的函数
        contract = self.contract[contract_name]
        try:
            func = contract.functions.__getattribute__(function)
        except AttributeError:
            return "{} there is no {} function".format(contract_name, function)
        # 准备参数
        inputs = contract.abi[function]['inputs']
        param = self.format_param(param, inputs)
        # 增加参数
        func = func() if len(param) == 0 else func(*param)
        # 静态函数
        if function in self.contract[contract_name].view_funcs:
            addr = self.valid_address(base_config.main_address)
            return func.call({"from": addr})
        # 需要上链的函数
        if self.last_tx is None or self.get_for_receipt(
                self.last_tx) is not None:
            tx = self._build_transaction(func)
            res = self._sign_and_send_rawtransaction(transaction=tx)
            self.last_tx = res
            print("Call successful , transaction hash:")
            return res
        else:
            print(
                "The last transaction was not confirmed , please call get_for_receipt to view the last transaction"
            )
            return self.last_tx

    def format_param(self, param, inputs):
        if isinstance(param, list):
            res = param
        else:
            res = list(param)
        if len(param) != len(inputs):
            return "Less parameters"
        for i in range(len(inputs)):
            _type = inputs[i].get('type')
            # if _type.endswith("[]"):
            #     return "Array arguments are not recommended for command-line input, use http://remix.ethereum.org/ " \
            #            "manually "
            if _type in ['uint256', 'uint8']:
                res[i] = int(param[i])
            elif 'bool' == _type:
                res[i] = bool(param[i])
            elif 'address' == _type:
                res[i] = self.valid_address(param[i])
            elif 'bytes16' == _type:
                # res[i] = self.web3.toHex(hexstr=param[i])
                res[i] = param[i]
            else:
                continue
        return res

    def get_last_call_info(self):
        if self.last_tx is None:
            return None
        return self.get_for_receipt(self.last_tx)
Exemple #3
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)
Exemple #4
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
Exemple #5
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()