Beispiel #1
0
 def test_betting_market_create(self):
     op = operations.Betting_market_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "group_id":
             "1.0.1241",
             "payout_condition": [["en", "Foo == Bar"],
                                  ["zh_Hans", "Foo == Bar"]],
             "asset_id":
             "1.3.10",
             "prefix":
             prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c804570132000000000000000000d904"
                "0000000000010202656e0a466f6f203d3d20426172077a"
                "685f48616e730a466f6f203d3d204261720a0000011f33"
                "a517c8eec3f3d8eaf9653d96037bed0feb3ae6496a6fde"
                "201816de06187fb4768be89dc7092626b816440f41d7b0"
                "92be3cc1b54eb340868a0638ddd93b4448")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #2
0
    def constructTx(self):
        """ Construct the actual transaction and store it in the class's dict
            store
        """
        ops = list()
        for op in self.ops:
            if isinstance(op, ProposalBuilder):
                # This operation is a proposal an needs to be deal with
                # differently
                proposals = op.get_raw()
                if proposals:
                    ops.append(proposals)
            else:
                # otherwise, we simply wrap ops into Operations
                ops.extend([Operation(op)])

        # We now wrap everything into an actual transaction
        ops = transactions.addRequiredFees(self.blockchain.rpc,
                                           ops,
                                           asset_id=self.fee_asset_id)
        expiration = transactions.formatTimeFromNow(
            self.expiration or self.blockchain.expiration)
        ref_block_num, ref_block_prefix = transactions.getBlockParams(
            self.blockchain.rpc)
        self.tx = Signed_Transaction(ref_block_num=ref_block_num,
                                     ref_block_prefix=ref_block_prefix,
                                     expiration=expiration,
                                     operations=ops)
        super(TransactionBuilder, self).update(self.tx.json())
        self._unset_require_reconstruction()
Beispiel #3
0
 def test_bet_place(self):
     op = operations.Bet_place(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "bettor_id": "1.2.1241",
             "betting_market_id": "1.21.1",
             "amount_to_bet": 100000,
             "amount_to_win": 20000,
             "amount_reserved_for_fees": 100000,
             "back_or_lay": "back",
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c804570133000000000000000000d909"
                "01a086010000000000204e000000000000a08601000000"
                "0000000000011f0fcb636b68993dde7b680f9b34ea375e"
                "2790b1b6a43621e2048712f21d2868fd553851b5254b5e"
                "a2d4995e535813a4d8f76b18bb62ad2722a4b2bb83558c"
                "55e0")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #4
0
 def test_event_create(self):
     op = operations.Event_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "season": [["en", "2016-17"]],
             "start_time": "2017-03-29T09:15:05",
             "event_group_id": "1.0.1241",
             "competitors": ["0.0.0", "0.0.1"],
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c8045701300000000000000000000001026"
                "56e07323031362d313701197bdb58d9040000000000010200"
                "0000000000000001000000000000000000011f2f6eccc426e"
                "56925b29293610505598a8580dc56fc594fef541d25a7cfc8"
                "120d7b82dc6fb929bd6bb1fb8f2ab976559ea29c9adc7a9b5"
                "df9788b909c7fafe232")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #5
0
 def test_betting_market_group_create(self):
     op = operations.Betting_market_group_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "event_id": "1.0.1241",
             "options": [2, {
                 "score": 100
             }],
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c804570131000000000000000000d904000"
                "0000000010264000000000001206e69065a3cd673843f4a66"
                "000d7143b2a10f27015d4c49600ffb5c94f6fc95fe40f3577"
                "264b9288b44e4fe3e0aa5397d1c7973054cc55c6bb611c23b"
                "397f5bb0")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #6
0
 def test_competitor_create(self):
     op = operations.Competitor_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "name": [["en", "Fuerth"], ["de", "Greuther Fürth"]],
             "sport_id": "1.0.1241",
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c80457012e000000000000000000020264"
                "650f47726575746865722046c3bc72746802656e06467565"
                "727468d9040000000000010000012068e0417811ad383306"
                "1dde84281b17daf22e8dfe879506ee06eb6d9c324297a811"
                "e04fa8e5983001bb7eee47d3e9fd0e7c48590c10abfa6a6f"
                "2a33ed50a2d424")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #7
0
 def test_event_group_create(self):
     op = operations.Event_group_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "name": [["en", "NHL"], ["zh_Hans", "國家冰球聯盟"]],
             "sport_id": "1.0.1241",
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c80457012f000000000000000000020265"
                "6e034e484c077a685f48616e7312e59c8be5aeb6e586b0e7"
                "9083e881afe79b9fd9040000000000010000011f15a6cb74"
                "7df1d9bb3e7e607d8094624b3f27010ad461dd8d833590b0"
                "e0f72c946082083f90686e9bc225f5b28fd50c63c8150b8c"
                "45956c336a182702e17d800d")
     self.assertEqual(compare[:-130], txWire[:-130])
    def constructTx(self):
        """ Construct the actual transaction and store it in the class's dict
            store
        """
        if self.peerplays.proposer:
            ops = [operations.Op_wrapper(op=o) for o in list(self.ops)]
            proposer = Account(
                self.peerplays.proposer,
                peerplays_instance=self.peerplays
            )
            ops = operations.Proposal_create(**{
                "fee": {"amount": 0, "asset_id": "1.3.0"},
                "fee_paying_account": proposer["id"],
                "expiration_time": transactions.formatTimeFromNow(
                    self.peerplays.proposal_expiration),
                "proposed_ops": [o.json() for o in ops],
                "extensions": []
            })
            ops = [Operation(ops)]
        else:
            ops = [Operation(o) for o in list(self.ops)]

        ops = transactions.addRequiredFees(self.peerplays.rpc, ops)
        expiration = transactions.formatTimeFromNow(self.peerplays.expiration)
        ref_block_num, ref_block_prefix = transactions.getBlockParams(self.peerplays.rpc)
        tx = Signed_Transaction(
            ref_block_num=ref_block_num,
            ref_block_prefix=ref_block_prefix,
            expiration=expiration,
            operations=ops
        )
        super(TransactionBuilder, self).__init__(tx.json())
Beispiel #9
0
    def test_Transfer(self):
        pub = format(account.PrivateKey(wif).pubkey, prefix)
        from_account_id = "1.2.0"
        to_account_id = "1.2.1"
        amount = 1000000
        asset_id = "1.3.4"
        message = "abcdefgABCDEFG0123456789"
        nonce = "5862723643998573708"

        fee = objects.Asset(amount=0, asset_id="1.3.0")
        amount = objects.Asset(amount=int(amount), asset_id=asset_id)
        encrypted_memo = memo.encode_memo(
            account.PrivateKey(wif), account.PublicKey(pub, prefix=prefix),
            nonce, message)
        op = operations.Transfer(
            **{
                "fee": fee,
                "from": from_account_id,
                "to": to_account_id,
                "amount": amount,
                "memo": {
                    "from": pub,
                    "to": pub,
                    "nonce": nonce,
                    "message": encrypted_memo,
                },
                "prefix": prefix
            })
        ops = [Operation(op)]
        tx = Signed_Transaction(ref_block_num=ref_block_num,
                                ref_block_prefix=ref_block_prefix,
                                expiration=expiration,
                                operations=ops)
        tx = tx.sign([wif], chain=prefix)
        tx.verify([PrivateKey(wif).pubkey], prefix)
        txWire = hexlify(bytes(tx)).decode("ascii")

        compare = ("f68585abf4dce7c804570100000000000000000000000140420"
                   "f0000000000040102c0ded2bc1f1305fb0faac5e6c03ee3a192"
                   "4234985427b6167ca569d13df435cf02c0ded2bc1f1305fb0fa"
                   "ac5e6c03ee3a1924234985427b6167ca569d13df435cf8c94d1"
                   "9817945c5120fa5b6e83079a878e499e2e52a76a7739e9de409"
                   "86a8e3bd8a68ce316cee50b210000011f39e3fa7071b795491e"
                   "3b6851d61e7c959be92cc7deb5d8491cf1c3c8c99a1eb44553c"
                   "348fb8f5001a78b18233ac66727e32fc776d48e92d9639d64f6"
                   "8e641948")
        self.assertEqual(compare[:-130], txWire[:-130])
    def doit(self, printWire=False):
        ops = [Operation(self.op)]
        tx = Signed_Transaction(
            ref_block_num=ref_block_num,
            ref_block_prefix=ref_block_prefix,
            expiration=expiration,
            operations=ops,
        )
        tx = tx.sign([wif], chain=prefix)
        tx.verify([PrivateKey(wif).pubkey], prefix)
        txWire = hexlify(bytes(tx)).decode("ascii")
        if printWire:
            print()
            print(txWire)
            print()
        self.assertEqual(self.cm[:-130], txWire[:-130])

        if TEST_AGAINST_CLI_WALLET:
            from grapheneapi.grapheneapi import GrapheneAPI

            rpc = GrapheneAPI("localhost", 8092)
            self.cm = rpc.serialize_transaction(tx.json())
            # print("soll: %s" % self.cm[:-130])
            # print("ist:  %s" % txWire[:-130])
            # print(txWire[:-130] == self.cm[:-130])
            self.assertEqual(self.cm[:-130], txWire[:-130])

        # Test against Bitshares backened
        live = peerplays.rpc.get_transaction_hex(tx.json())

        # Compare expected result with online result
        self.assertEqual(live[:-130], txWire[:-130])

        # Compare expected result with online backend
        self.assertEqual(live[:-130], self.cm[:-130])
    def compareConstructedTX(self):
        self.op = operations.Balance_claim(
            **{
                "fee": {"amount": 0, "asset_id": "1.3.0"},
                "deposit_to_account": "1.2.0",
                "balance_to_claim": "1.15.0",
                "balance_owner_key": prefix + "1111111111111111111111111111111114T1Anm",
                "total_claimed": {"amount": 0, "asset_id": "1.3.0"},
                "prefix": prefix,
            }
        )

        ops = [Operation(self.op)]
        tx = Signed_Transaction(
            ref_block_num=ref_block_num,
            ref_block_prefix=ref_block_prefix,
            expiration=expiration,
            operations=ops,
        )
        tx = tx.sign([wif], chain=prefix)
        tx.verify([PrivateKey(wif).pubkey], prefix)
        txWire = hexlify(bytes(tx)).decode("ascii")
        print("=" * 80)
        pprint(tx.json())
        print("=" * 80)

        from grapheneapi.grapheneapi import GrapheneAPI

        rpc = GrapheneAPI("localhost", 8092)
        self.cm = rpc.serialize_transaction(tx.json())
        print("soll: %s" % self.cm)
        print("ist:  %s" % txWire)
        print(txWire[:-130] == self.cm[:-130])
        self.assertEqual(self.cm[:-130], txWire[:-130])
Beispiel #12
0
 def test_create_proposal(self):
     op = operations.Proposal_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "fee_paying_account":
             "1.2.0",
             "expiration_time":
             "1970-01-01T00:00:00",
             "proposed_ops": [{
                 "op": [
                     0, {
                         "fee": {
                             "amount": 0,
                             "asset_id": "1.3.0"
                         },
                         "from": "1.2.0",
                         "to": "1.2.0",
                         "amount": {
                             "amount": 0,
                             "asset_id": "1.3.0"
                         },
                         "extensions": []
                     }
                 ]
             }],
             "extensions": []
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c80457011600000000000000000000000000"
                "00010000000000000000000000000000000000000000000000"
                "00000001204baf7f11a7ff12337fc097ac6e82e7b68f82f02c"
                "c7e24231637c88a91ae5716674acec8a1a305073165c65e520"
                "a64769f5f62c0301ce21ab4f7c67a6801b4266")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #13
0
    def sign(self):
        """ Sign a provided transaction with the provided key(s)

            :param dict tx: The transaction to be signed and returned
            :param string wifs: One or many wif keys to use for signing
                a transaction. If not present, the keys will be loaded
                from the wallet as defined in "missing_signatures" key
                of the transactions.
        """
        self.constructTx()

        if "operations" not in self or not self["operations"]:
            return

        # Legacy compatibility!
        # If we are doing a proposal, obtain the account from the proposer_id
        if self.blockchain.proposer:
            proposer = Account(self.blockchain.proposer,
                               blockchain_instance=self.blockchain)
            self.wifs = set()
            self.signing_accounts = list()
            self.appendSigner(proposer["id"], "active")

        # We need to set the default prefix, otherwise pubkeys are
        # presented wrongly!
        if self.blockchain.rpc:
            operations.default_prefix = (
                self.blockchain.rpc.chain_params["prefix"])
        elif "blockchain" in self:
            operations.default_prefix = self["blockchain"]["prefix"]

        try:
            signedtx = Signed_Transaction(**self.json())
        except:
            raise ValueError("Invalid TransactionBuilder Format")

        if not any(self.wifs):
            raise MissingKeyError

        signedtx.sign(self.wifs, chain=self.blockchain.rpc.chain_params)
        self["signatures"].extend(signedtx.json().get("signatures"))
        return signedtx
Beispiel #14
0
 def test_proposal_update(self):
     op = operations.Proposal_update(
         **{
             'fee_paying_account': "1.2.1",
             'proposal': "1.10.90",
             'active_approvals_to_add': ["1.2.5"],
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c804570117000000000000000000015a01050000000"
                "000000001200b28528d1436564f4b4a9faf38b77c17d69ea85476076e"
                "bafebbad9733ac014411b044a7570ef103a518d2e17f7250e1cd8e31c"
                "f19272395c8fe9bbce0b4bfb4")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #15
0
 def test_sport_create(self):
     op = operations.Sport_create(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "name": [["en", "Football"], ["de", "Fußball"]],
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c80457012d000000000000000000020264650"
                "84675c39f62616c6c02656e08466f6f7462616c6c0000011f14"
                "eb892a0c4a6c28e0a54852d45526b0d8e017edc4eaac1c0c54c"
                "6f944ff1d7e5e909157257fe6e71a4532563564c8c063f38846"
                "5f8a9420459d5b6cb1fdfcc1")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #16
0
 def test_upgrade_account(self):
     op = operations.Account_upgrade(
         **{
             "fee": {
                 "amount": 0,
                 "asset_id": "1.3.0"
             },
             "account_to_upgrade": "1.2.0",
             "upgrade_to_lifetime_member": True,
             "prefix": prefix,
         })
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c804570108000000000000000000000100000"
                "11f4e42562ada1d3fed8f8eb51dd58117e3a4024959c46955a0"
                "0d2a7e7e8b40ae7204f4617913aaaf028248d43e8c3463b8776"
                "0ca569007dba99a2c49de75bd69b3")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #17
0
    def compareConstructedTX(self):
        op = operations.Proposal_update(
            **{
                'fee_paying_account': "1.2.1",
                'proposal': "1.10.90",
                'active_approvals_to_add': ["1.2.5"],
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
            })
        """
        op = operations.Betting_market_resolve(**{
            "fee": {"amount": 0, "asset_id": "1.3.0"},
            "betting_market_id": "1.21.1",
            "resolution": "win",
            "prefix": prefix,
        })
        op = operations.Bet_cancel_operation(**{
            "fee": {"amount": 0, "asset_id": "1.3.0"},
            "bettor_id": "1.2.1241",
            "bet_to_cancel": "1.22.10",
            "prefix": prefix,
        })
        """
        ops = [Operation(op)]
        tx = Signed_Transaction(ref_block_num=ref_block_num,
                                ref_block_prefix=ref_block_prefix,
                                expiration=expiration,
                                operations=ops)
        tx = tx.sign([wif], chain=prefix)
        tx.verify([PrivateKey(wif).pubkey], prefix)
        txWire = hexlify(bytes(tx)).decode("ascii")
        print("=" * 80)
        pprint(tx.json())
        print("=" * 80)

        from grapheneapi.grapheneapi import GrapheneAPI
        rpc = GrapheneAPI("localhost", 8092)
        compare = rpc.serialize_transaction(tx.json())
        print(compare[:-130])
        print(txWire[:-130])
        print(txWire[:-130] == compare[:-130])
        self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #18
0
    def compareConstructedTX(self):
        self.op = operations.Bet_place(
            **{
                "fee": {
                    "amount": 0,
                    "asset_id": "1.3.0"
                },
                "bettor_id": "1.2.1241",
                "betting_market_id": "1.21.1",
                "amount_to_bet": {
                    "amount": 1000,
                    "asset_id": "1.3.1"
                },
                "backer_multiplier": 2 * GRAPHENE_BETTING_ODDS_PRECISION,
                "back_or_lay": "lay",
                "prefix": prefix,
            })
        ops = [Operation(self.op)]
        """
        from peerplays import PeerPlays
        ppy = PeerPlays()
        ops = transactions.addRequiredFees(ppy.rpc, ops)
        """
        tx = Signed_Transaction(ref_block_num=ref_block_num,
                                ref_block_prefix=ref_block_prefix,
                                expiration=expiration,
                                operations=ops)
        tx = tx.sign([wif], chain=prefix)
        tx.verify([PrivateKey(wif).pubkey], prefix)
        txWire = hexlify(bytes(tx)).decode("ascii")
        print("=" * 80)
        pprint(tx.json())
        print("=" * 80)

        from grapheneapi.grapheneapi import GrapheneAPI
        rpc = GrapheneAPI("localhost", 8092)
        self.cm = rpc.serialize_transaction(tx.json())
        print("soll: %s" % self.cm[:-130])
        print("ist:  %s" % txWire[:-130])
        print(txWire[:-130] == self.cm[:-130])
        self.assertEqual(self.cm[:-130], txWire[:-130])
Beispiel #19
0
    def doit(self, printWire=False):
        ops = [Operation(self.op)]
        tx = Signed_Transaction(ref_block_num=ref_block_num,
                                ref_block_prefix=ref_block_prefix,
                                expiration=expiration,
                                operations=ops)
        tx = tx.sign([wif], chain=prefix)
        tx.verify([PrivateKey(wif).pubkey], prefix)
        txWire = hexlify(bytes(tx)).decode("ascii")
        if printWire:
            print()
            print(txWire)
            print()
        self.assertEqual(self.cm[:-130], txWire[:-130])

        if TEST_AGAINST_CLI_WALLET:
            from grapheneapi.grapheneapi import GrapheneAPI
            rpc = GrapheneAPI("localhost", 8092)
            self.cm = rpc.serialize_transaction(tx.json())
            # print("soll: %s" % self.cm[:-130])
            # print("ist:  %s" % txWire[:-130])
            # print(txWire[:-130] == self.cm[:-130])
            self.assertEqual(self.cm[:-130], txWire[:-130])
class TransactionBuilder(dict):
    """ This class simplifies the creation of transactions by adding
        operations and signers.
    """
    def __init__(self, tx={}, peerplays_instance=None):
        self.peerplays = peerplays_instance or shared_peerplays_instance()
        self.clear()
        if not isinstance(tx, dict):
            raise ValueError("Invalid TransactionBuilder Format")
        super(TransactionBuilder, self).__init__(tx)

    def appendOps(self, ops):
        """ Append op(s) to the transaction builder

            :param list ops: One or a list of operations
        """
        if isinstance(ops, list):
            self.ops.extend(ops)
        else:
            self.ops.append(ops)

    def appendSigner(self, account, permission):
        """ Try to obtain the wif key from the wallet by telling which account
            and permission is supposed to sign the transaction
        """
        assert permission in ["active", "owner"], "Invalid permission"
        account = Account(account, peerplays_instance=self.peerplays)
        required_treshold = account[permission]["weight_threshold"]

        def fetchkeys(account, level=0):
            if level > 2:
                return []
            r = []
            for authority in account[permission]["key_auths"]:
                wif = self.peerplays.wallet.getPrivateKeyForPublicKey(
                    authority[0])
                if wif:
                    r.append([wif, authority[1]])

            if sum([x[1] for x in r]) < required_treshold:
                # go one level deeper
                for authority in account[permission]["account_auths"]:
                    auth_account = Account(authority[0],
                                           peerplays_instance=self.peerplays)
                    r.extend(fetchkeys(auth_account, level + 1))

            return r

        keys = fetchkeys(account)
        self.wifs.extend([x[0] for x in keys])

    def appendWif(self, wif):
        """ Add a wif that should be used for signing of the transaction.
        """
        if wif:
            try:
                PrivateKey(wif)
                self.wifs.append(wif)
            except:
                raise InvalidWifError

    def constructTx(self):
        """ Construct the actual transaction and store it in the class's dict
            store
        """
        if self.peerplays.proposer:
            ops = [operations.Op_wrapper(op=o) for o in list(self.ops)]
            proposer = Account(self.peerplays.proposer,
                               peerplays_instance=self.peerplays)
            ops = operations.Proposal_create(
                **{
                    "fee": {
                        "amount": 0,
                        "asset_id": "1.3.0"
                    },
                    "fee_paying_account":
                    proposer["id"],
                    "expiration_time":
                    transactions.formatTimeFromNow(
                        self.peerplays.proposal_expiration),
                    "proposed_ops": [o.json() for o in ops],
                    "extensions": []
                })
            ops = [Operation(ops)]
        else:
            ops = [Operation(o) for o in list(self.ops)]

        ops = transactions.addRequiredFees(self.peerplays.rpc, ops)
        expiration = transactions.formatTimeFromNow(self.peerplays.expiration)
        ref_block_num, ref_block_prefix = transactions.getBlockParams(
            self.peerplays.rpc)
        self.tx = Signed_Transaction(ref_block_num=ref_block_num,
                                     ref_block_prefix=ref_block_prefix,
                                     expiration=expiration,
                                     operations=ops)
        super(TransactionBuilder, self).__init__(self.tx.json())

    def sign(self):
        """ Sign a provided transaction witht he provided key(s)

            :param dict tx: The transaction to be signed and returned
            :param string wifs: One or many wif keys to use for signing
                a transaction. If not present, the keys will be loaded
                from the wallet as defined in "missing_signatures" key
                of the transactions.
        """
        self.constructTx()

        # If we are doing a proposal, obtain the account from the proposer_id
        if self.peerplays.proposer:
            proposer = Account(self.peerplays.proposer,
                               peerplays_instance=self.peerplays)
            self.wifs = []
            self.appendSigner(proposer["id"], "active")

        # We need to set the default prefix, otherwise pubkeys are
        # presented wrongly!
        if self.peerplays.rpc:
            operations.default_prefix = self.peerplays.rpc.chain_params[
                "prefix"]
        elif "blockchain" in self:
            operations.default_prefix = self["blockchain"]["prefix"]

        try:
            signedtx = Signed_Transaction(**self.json())
        except:
            raise ValueError("Invalid TransactionBuilder Format")

        if not any(self.wifs):
            raise MissingKeyError

        signedtx.sign(self.wifs, chain=self.peerplays.rpc.chain_params)
        self["signatures"].extend(signedtx.json().get("signatures"))

    def verify_authority(self):
        """ Verify the authority of the signed transaction
        """
        try:
            if not self.peerplays.rpc.verify_authority(self.json()):
                raise InsufficientAuthorityError
        except Exception as e:
            raise e

    def broadcast(self):
        """ Broadcast a transaction to the PeerPlays network

            :param tx tx: Signed transaction to broadcast
        """
        if not "signatures" in self or not self["signatures"]:
            self.sign()

        if self.peerplays.nobroadcast:
            log.warning("Not broadcasting anything!")
            return self

        # Broadcast
        try:
            self.peerplays.rpc.broadcast_transaction(self.json(),
                                                     api="network_broadcast")
        except Exception as e:
            raise e

        self.clear()

        return self

    def clear(self):
        """ Clear the transaction builder and start from scratch
        """
        self.ops = []
        self.wifs = []
        super(TransactionBuilder, self).__init__({})

    def addSigningInformation(self, account, permission):
        """ This is a private method that adds side information to a
            unsigned/partial transaction in order to simplify later
            signing (e.g. for multisig or coldstorage)
        """
        self.constructTx()
        accountObj = Account(account)
        authority = accountObj[permission]
        # We add a required_authorities to be able to identify
        # how to sign later. This is an array, because we
        # may later want to allow multiple operations per tx
        self.update({"required_authorities": {accountObj["name"]: authority}})
        for account_auth in authority["account_auths"]:
            account_auth_account = Account(account_auth[0])
            self["required_authorities"].update(
                {account_auth[0]: account_auth_account.get(permission)})

        # Try to resolve required signatures for offline signing
        self["missing_signatures"] = [x[0] for x in authority["key_auths"]]
        # Add one recursion of keys from account_auths:
        for account_auth in authority["account_auths"]:
            account_auth_account = Account(account_auth[0])
            self["missing_signatures"].extend(
                [x[0] for x in account_auth_account[permission]["key_auths"]])
        self["blockchain"] = self.peerplays.rpc.chain_params

    def json(self):
        """ Show the transaction as plain json
        """
        return dict(self)

    def appendMissingSignatures(self):
        """ Store which accounts/keys are supposed to sign the transaction

            This method is used for an offline-signer!
        """
        missing_signatures = self.get("missing_signatures", [])
        for pub in missing_signatures:
            wif = self.peerplays.wallet.getPrivateKeyForPublicKey(pub)
            if wif:
                self.appendWif(wif)
Beispiel #21
0
 def test_create_account(self):
     s = {
         "fee": {
             "amount": 1467634,
             "asset_id": "1.3.0"
         },
         "registrar": "1.2.33",
         "referrer": "1.2.27",
         "referrer_percent": 3,
         "name": "foobar-f124",
         "owner": {
             "weight_threshold":
             1,
             "account_auths": [],
             'key_auths':
             [[
                 prefix +
                 '6pbVDAjRFiw6fkiKYCrkz7PFeL7XNAfefrsREwg8MKpJ9VYV9x', 1
             ],
              [
                  prefix +
                  '6zLNtyFVToBsBZDsgMhgjpwysYVbsQD6YhP3kRkQhANUB4w7Qp', 1
              ]],
             "address_auths": []
         },
         "active": {
             "weight_threshold":
             1,
             "account_auths": [],
             'key_auths':
             [[
                 prefix +
                 '6pbVDAjRFiw6fkiKYCrkz7PFeL7XNAfefrsREwg8MKpJ9VYV9x', 1
             ],
              [
                  prefix +
                  '6zLNtyFVToBsBZDsgMhgjpwysYVbsQD6YhP3kRkQhANUB4w7Qp', 1
              ],
              [
                  prefix +
                  '8CemMDjdUWSV5wKotEimhK6c4dY7p2PdzC2qM1HpAP8aLtZfE7', 1
              ]],
             "address_auths": []
         },
         "options": {
             "memo_key":
             prefix + '5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE',
             "voting_account": "1.2.5",
             "num_witness": 0,
             "num_committee": 0,
             "votes": [],
             "extensions": []
         },
         "extensions": {},
         "prefix": prefix
     }
     op = operations.Account_create(**s)
     ops = [Operation(op)]
     tx = Signed_Transaction(ref_block_num=ref_block_num,
                             ref_block_prefix=ref_block_prefix,
                             expiration=expiration,
                             operations=ops)
     tx = tx.sign([wif], chain=prefix)
     tx.verify([PrivateKey(wif).pubkey], prefix)
     txWire = hexlify(bytes(tx)).decode("ascii")
     compare = ("f68585abf4dce7c804570105f26416000000000000211b03000b666f"
                "6f6261722d6631323401000000000202fe8cc11cc8251de6977636b5"
                "5c1ab8a9d12b0b26154ac78e56e7c4257d8bcf6901000314aa202c91"
                "58990b3ec51a1aa49b2ab5d300c97b391df3beb34bb74f3c62699e01"
                "000001000000000303b453f46013fdbccb90b09ba169c388c34d8445"
                "4a3b9fbec68d5a7819a734fca0010002fe8cc11cc8251de6977636b5"
                "5c1ab8a9d12b0b26154ac78e56e7c4257d8bcf6901000314aa202c91"
                "58990b3ec51a1aa49b2ab5d300c97b391df3beb34bb74f3c62699e01"
                "0000024ab336b4b14ba6d881675d1c782912783c43dbbe31693aa710"
                "ac1896bd7c3d61050000000000000000011f61ad276120bc3f189296"
                "2bfff7db5e8ce04d5adec9309c80529e3a978a4fa1073225a6d56929"
                "e34c9d2a563e67a8f4a227e4fadb4a3bb6ec91bfdf4e57b80efd")
     self.assertEqual(compare[:-130], txWire[:-130])
Beispiel #22
0
class TransactionBuilder(dict):
    """ This class simplifies the creation of transactions by adding
        operations and signers.
    """
    def __init__(self, tx={}, proposer=None, **kwargs):
        BlockchainInstance.__init__(self, **kwargs)
        self.clear()
        if tx and isinstance(tx, dict):
            super(TransactionBuilder, self).__init__(tx)
            # Load operations
            self.ops = tx["operations"]
            self._require_reconstruction = False
        else:
            self._require_reconstruction = True
            self.set_fee_asset(kwargs.get("fee_asset", None))
        self.set_expiration(
            kwargs.get("expiration", self.blockchain.expiration) or 30)

    def set_expiration(self, p):
        self.expiration = p

    def is_empty(self):
        return not (len(self.ops) > 0)

    def list_operations(self):
        return [Operation(o) for o in self.ops]

    def _is_signed(self):
        return "signatures" in self and self["signatures"]

    def _is_constructed(self):
        return "expiration" in self and self["expiration"]

    def _is_require_reconstruction(self):
        return self._require_reconstruction

    def _set_require_reconstruction(self):
        self._require_reconstruction = True

    def _unset_require_reconstruction(self):
        self._require_reconstruction = False

    def __repr__(self):
        return str(self)

    def __str__(self):
        return str(self.json())

    def __getitem__(self, key):
        if key not in self:
            self.constructTx()
        return dict(self).__getitem__(key)

    def get_parent(self):
        """ TransactionBuilders don't have parents, they are their own parent
        """
        return self

    def json(self):
        """ Show the transaction as plain json
        """
        if not self._is_constructed() or self._is_require_reconstruction():
            self.constructTx()
        return dict(self)

    def appendOps(self, ops, append_to=None):
        """ Append op(s) to the transaction builder

            :param list ops: One or a list of operations
        """
        if isinstance(ops, list):
            self.ops.extend(ops)
        else:
            self.ops.append(ops)
        self._set_require_reconstruction()

    def appendSigner(self, accounts, permission):
        """ Try to obtain the wif key from the wallet by telling which accounts
            and permission is supposed to sign the transaction
        """

        # Let's define a helper function for recursion
        def fetchkeys(account, perm, level=0):
            if level > 2:
                return []
            r = []
            for authority in account[perm]["key_auths"]:
                try:
                    wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
                        authority[0])
                    r.append([wif, authority[1]])
                except Exception:
                    pass

            if sum([x[1] for x in r]) < required_treshold:
                # go one level deeper
                for authority in account[perm]["account_auths"]:
                    auth_account = Account(authority[0],
                                           blockchain_instance=self.blockchain)
                    r.extend(fetchkeys(auth_account, perm, level + 1))

            return r

        assert permission in ["active", "owner"], "Invalid permission"
        if self.blockchain.wallet.locked():
            raise WalletLocked()
        if not isinstance(accounts, (list, tuple, set)):
            accounts = [accounts]

        for account in accounts:
            # Now let's actually deal with the accounts
            if account not in self.signing_accounts:
                # is the account an instance of public key?
                if isinstance(account, PublicKey):
                    self.wifs.add(
                        self.blockchain.wallet.getPrivateKeyForPublicKey(
                            str(account)))
                # ... or should we rather obtain the keys from an account name
                else:
                    account = Account(account,
                                      blockchain_instance=self.blockchain)
                    required_treshold = account[permission]["weight_threshold"]
                    keys = fetchkeys(account, permission)
                    # If we couldn't find an active key, let's try overwrite it
                    # with an owner key
                    if not keys and permission != "owner":
                        keys.extend(fetchkeys(account, "owner"))
                    for x in keys:
                        self.wifs.add(x[0])

                self.signing_accounts.append(account)

    def appendWif(self, wif):
        """ Add a wif that should be used for signing of the transaction.
        """
        if wif:
            try:
                PrivateKey(wif)
                self.wifs.add(wif)
            except:
                raise InvalidWifError

    def set_fee_asset(self, fee_asset):
        """ Set asset to fee
        """
        from .amount import Asset
        if isinstance(fee_asset, Asset):
            self.fee_asset_id = fee_asset["id"]
        elif fee_asset:
            self.fee_asset_id = fee_asset
        else:
            self.fee_asset_id = "1.3.0"

    def constructTx(self):
        """ Construct the actual transaction and store it in the class's dict
            store
        """
        ops = list()
        for op in self.ops:
            if isinstance(op, ProposalBuilder):
                # This operation is a proposal an needs to be deal with
                # differently
                proposals = op.get_raw()
                if proposals:
                    ops.append(proposals)
            else:
                # otherwise, we simply wrap ops into Operations
                ops.extend([Operation(op)])

        # We now wrap everything into an actual transaction
        ops = transactions.addRequiredFees(self.blockchain.rpc,
                                           ops,
                                           asset_id=self.fee_asset_id)
        expiration = transactions.formatTimeFromNow(
            self.expiration or self.blockchain.expiration)
        ref_block_num, ref_block_prefix = transactions.getBlockParams(
            self.blockchain.rpc)
        self.tx = Signed_Transaction(ref_block_num=ref_block_num,
                                     ref_block_prefix=ref_block_prefix,
                                     expiration=expiration,
                                     operations=ops)
        super(TransactionBuilder, self).update(self.tx.json())
        self._unset_require_reconstruction()

    def sign(self):
        """ Sign a provided transaction with the provided key(s)

            :param dict tx: The transaction to be signed and returned
            :param string wifs: One or many wif keys to use for signing
                a transaction. If not present, the keys will be loaded
                from the wallet as defined in "missing_signatures" key
                of the transactions.
        """
        self.constructTx()

        if "operations" not in self or not self["operations"]:
            return

        # Legacy compatibility!
        # If we are doing a proposal, obtain the account from the proposer_id
        if self.blockchain.proposer:
            proposer = Account(self.blockchain.proposer,
                               blockchain_instance=self.blockchain)
            self.wifs = set()
            self.signing_accounts = list()
            self.appendSigner(proposer["id"], "active")

        # We need to set the default prefix, otherwise pubkeys are
        # presented wrongly!
        if self.blockchain.rpc:
            operations.default_prefix = (
                self.blockchain.rpc.chain_params["prefix"])
        elif "blockchain" in self:
            operations.default_prefix = self["blockchain"]["prefix"]

        try:
            signedtx = Signed_Transaction(**self.json())
        except:
            raise ValueError("Invalid TransactionBuilder Format")

        if not any(self.wifs):
            raise MissingKeyError

        signedtx.sign(self.wifs, chain=self.blockchain.rpc.chain_params)
        self["signatures"].extend(signedtx.json().get("signatures"))
        return signedtx

    def verify_authority(self):
        """ Verify the authority of the signed transaction
        """
        try:
            if not self.blockchain.rpc.verify_authority(self.json()):
                raise InsufficientAuthorityError
        except Exception as e:
            raise e

    def broadcast(self):
        """ Broadcast a transaction to the blockchain network

            :param tx tx: Signed transaction to broadcast
        """
        # Cannot broadcast an empty transaction
        if not self._is_signed():
            self.sign()

        if "operations" not in self or not self["operations"]:
            return

        ret = self.json()

        if self.blockchain.nobroadcast:
            log.warning("Not broadcasting anything!")
            self.clear()
            return ret

        # Broadcast
        try:
            if self.blockchain.blocking:
                ret = self.blockchain.rpc.broadcast_transaction_synchronous(
                    ret, api="network_broadcast")
                ret.update(**ret.get("trx"))
            else:
                self.blockchain.rpc.broadcast_transaction(
                    ret, api="network_broadcast")
        except Exception as e:
            raise e
        finally:
            self.clear()

        return ret

    def clear(self):
        """ Clear the transaction builder and start from scratch
        """
        self.ops = []
        self.wifs = set()
        self.signing_accounts = []
        # This makes sure that _is_constructed will return False afterwards
        self["expiration"] = None
        super(TransactionBuilder, self).__init__({})

    def addSigningInformation(self, accounts, permission):
        """ This is a private method that adds side information to a
            unsigned/partial transaction in order to simplify later
            signing (e.g. for multisig or coldstorage)

            FIXME: Does not work with owner keys!
        """
        self.constructTx()
        self["blockchain"] = self.blockchain.rpc.chain_params

        if isinstance(accounts, PublicKey):
            self["missing_signatures"] = [str(accounts)]
        else:
            if not isinstance(accounts, list):
                accounts = [accounts]
            for account in accounts:
                accountObj = Account(account)
                authority = accountObj[permission]
                # We add a required_authorities to be able to identify
                # how to sign later. This is an array, because we
                # may later want to allow multiple operations per tx
                if "required_authorities" not in self:
                    self["required_authorities"] = dict()
                if "missing_signatures" not in self:
                    self["missing_signatures"] = list()

                self["required_authorities"].update(
                    {accountObj["name"]: authority})
                for account_auth in authority["account_auths"]:
                    account_auth_account = Account(account_auth[0])
                    self["required_authorities"].update({
                        account_auth[0]:
                        account_auth_account.get(permission)
                    })

                # Try to resolve required signatures for offline signing
                self["missing_signatures"].extend(
                    [x[0] for x in authority["key_auths"]])
                # Add one recursion of keys from account_auths:
                for account_auth in authority["account_auths"]:
                    account_auth_account = Account(account_auth[0])
                    self["missing_signatures"].extend([
                        x[0]
                        for x in account_auth_account[permission]["key_auths"]
                    ])

    def appendMissingSignatures(self):
        """ Store which accounts/keys are supposed to sign the transaction

            This method is used for an offline-signer!
        """
        missing_signatures = self.get("missing_signatures", [])
        for pub in missing_signatures:
            wif = self.blockchain.wallet.getPrivateKeyForPublicKey(pub)
            if wif:
                self.appendWif(wif)