def test_simple_transfer(self): EXPECTED_DIGEST = "257c5e1de3a0a895d66d57792f1a44425336bb05bc6c8479be83b4572e1b4d45" EXPECTED_PAYLOAD = \ "a1640000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d44235130ac5aab442e39f" \ "9aa27118956695229212dd2f1ab5b714e9f6bd581511c1010000000000000000000000000418c2a33af8bd2cba7f" \ "a714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758b" \ "cc4961bbdc75a0251c" # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_transfer(IDENTITIES[1], 256) payload.add_signer(IDENTITIES[0]) # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def test_smart_contract(self): EXPECTED_DIGEST = "9ea094e71cbe846192429db3d7e8b02b649730c8b525c3268eb9ff5633c27130" EXPECTED_PAYLOAD = \ "a1604000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \ "e6672a9d98da667e5dc25b2bca8acf9644a7ac0797f01cb5968abf39de011df2066c61756e636802676f00000000" \ "000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c25" \ "8cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c" # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_signer(IDENTITIES[0]) payload.charge_rate = 1000 payload.charge_limit = 1000000 payload.target_contract(Address(IDENTITIES[4]), BitVector()) payload.action = 'launch' payload.data = 'go'.encode('ascii') # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def test_multiple_transfers(self): EXPECTED_DIGEST = "35c19ceff72218a36f9807c370e5625efc36e43ce4e9f2047f1b820162b8b3d9" EXPECTED_PAYLOAD = \ "a1660000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4014235130ac5aab442e3" \ "9f9aa27118956695229212dd2f1ab5b714e9f6bd581511c1010020f478c7f74b50c187bf9a8836f382bd62977bae" \ "eaf19625608e7e912aa60098c10200da2e9c3191e3768d1c59ea43f6318367ed9b21e6974f46a60d0dd8976740af" \ "6dc2000186a000000000000000000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe" \ "08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c" # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_transfer(IDENTITIES[1], 256) payload.add_transfer(IDENTITIES[2], 512) payload.add_transfer(IDENTITIES[3], 100000) payload.add_signer(IDENTITIES[0]) # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def send_signed_transaction(self, tx_signed: Any) -> Optional[str]: """ Send a signed transaction and wait for confirmation. :param tx_signed: the signed transaction """ encoded_tx = transaction.encode_transaction(tx_signed) endpoint = "transfer" if tx_signed.transfers is not None else "create" return self.api.tokens._post_tx_json( # pylint: disable=protected-access encoded_tx, endpoint)
def action(self, contract_address: Address, action: str, fee: int, signer: Entity, *args, shard_mask: Optional[BitVector] = None): tx = ContractTxFactory.action(Address(signer), contract_address, action, fee, [signer], *args, shard_mask=shard_mask) tx.data = self._encode_msgpack_payload(*args) self._set_validity_period(tx) tx.sign(signer) encoded_tx = transaction.encode_transaction(tx) return self._post_tx_json(encoded_tx, None)
def submit_signed_tx(self, tx: Transaction): """ Appends signatures to a transaction and submits it, returning the transaction digest :param tx: A pre-assembled transaction :param signatures: A dict of signers signatures :return: The digest of the submitted transaction :raises: ApiError on any failures """ # encode transaction and append signatures encoded_tx = transaction.encode_transaction(tx) # submit and return digest return self._post_tx_json(encoded_tx, None)
def create(self, owner: Entity, contract: 'Contract', fee: int, shard_mask: Optional[BitVector] = None): ENDPOINT = 'create' logging.debug('Deploying contract', contract.address) tx = ContractTxFactory.create(Address(owner), contract, fee, [owner], shard_mask) self._set_validity_period(tx) tx.sign(owner) # encode and sign the transaction encoded_tx = transaction.encode_transaction(tx) # submit the transaction return self._post_tx_json(encoded_tx, ENDPOINT)
def test_contract_with_large_shard_mask(self): EXPECTED_DIGEST = "86a1c9e380fe5154243af3d50603aadb75327513373c0e2917b8319d3391b3ae" EXPECTED_PAYLOAD = \ "a1618000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \ "4041eaab0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840" \ "a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bb" \ "dc75a0251c" mask = BitVector(16) mask.set(15, 1) mask.set(14, 1) mask.set(13, 1) mask.set(11, 1) mask.set(9, 1) mask.set(7, 1) mask.set(5, 1) mask.set(3, 1) mask.set(1, 1) mask.set(0, 1) # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_signer(IDENTITIES[0]) payload.charge_rate = 1000 payload.charge_limit = 1000000 payload.valid_from = 100 payload.valid_until = 200 payload.target_chain_code('foo.bar.baz', mask) payload.action = 'launch' # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def submit_data(self, entity: Entity, contract_address: Address, fee: int, **kwargs): # build up the basic transaction information tx = self._create_skeleton_tx(fee) self._set_validity_period(tx) tx.from_address = Address(entity) tx.target_synergetic_data(contract_address, BitVector()) tx.action = 'data' tx.data = self._encode_json(dict(**kwargs)) tx.add_signer(entity) tx.sign(entity) # encode the transaction encoded_tx = transaction.encode_transaction(tx) # submit the transaction to the catch-all endpoint return self._post_tx_json(encoded_tx, None)
def collect_stake(self, entity: Entity, fee: int): """ Collect all stakes that have reached the end of the cooldown period :param entity: The entity object that desires to collect :return: The digest of the submitted transaction :raises: ApiError on any failures """ ENDPOINT = 'collectStake' tx = TokenTxFactory.collect_stake(entity, fee, [entity]) self._set_validity_period(tx) tx.sign(entity) # encode and sign the transaction encoded_tx = transaction.encode_transaction(tx) # submit the transaction return self._post_tx_json(encoded_tx, ENDPOINT)
def deed(self, entity: Entity, deed: Deed, fee: int): """ Sets the deed for a multi-sig account :param entity: The entity object to create a deed for :param deed: The deed to set :param signatories: The entities that will sign this action :return: The digest of the submitted transaction :raises: ApiError on any failures """ ENDPOINT = 'deed' tx = TokenTxFactory.deed(entity, deed, fee, [entity]) self._set_validity_period(tx) tx.sign(entity) encoded_tx = transaction.encode_transaction(tx) return self._post_tx_json(encoded_tx, ENDPOINT)
def add_stake(self, entity: Entity, amount: int, fee: int): """ Stakes a specific amount of :param entity: The entity object that desires to stake :param amount: The amount to stake :return: The digest of the submitted transaction :raises: ApiError on any failures """ ENDPOINT = 'addStake' tx = TokenTxFactory.add_stake(entity, amount, fee, [entity]) self._set_validity_period(tx) tx.sign(entity) # encode and sign the transaction encoded_tx = transaction.encode_transaction(tx) # submit the transaction return self._post_tx_json(encoded_tx, ENDPOINT)
def test_contract_with_4bit_shard_mask(self): EXPECTED_DIGEST = "e1ac018356792e492aaac92bf6928af1e47ed987761b81cafb51f1106f403eee" EXPECTED_PAYLOAD = \ "a1618000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \ "401c0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840a308" \ "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \ "a0251c" mask = BitVector(4) mask.set(3, 1) mask.set(2, 1) # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_signer(IDENTITIES[0]) payload.charge_rate = 1000 payload.charge_limit = 1000000 payload.valid_from = 100 payload.valid_until = 200 payload.target_chain_code('foo.bar.baz', mask) payload.action = 'launch' # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def test_validity_ranges(self): EXPECTED_DIGEST = "5451e302ba1fd323b623c1c9a0fc626b9c9249bb5d91ec60be1bb924efa3f1ac" EXPECTED_PAYLOAD = \ "a1670000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4024235130ac5aab442e3" \ "9f9aa27118956695229212dd2f1ab5b714e9f6bd581511c103e820f478c7f74b50c187bf9a8836f382bd62977bae" \ "eaf19625608e7e912aa60098c103e8da2e9c3191e3768d1c59ea43f6318367ed9b21e6974f46a60d0dd8976740af" \ "6dc103e8e6672a9d98da667e5dc25b2bca8acf9644a7ac0797f01cb5968abf39de011df2c103e864c0c8c103e8c2" \ "000f424000000000000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f" \ "4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c" # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_transfer(IDENTITIES[1], 1000) payload.add_transfer(IDENTITIES[2], 1000) payload.add_transfer(IDENTITIES[3], 1000) payload.add_transfer(IDENTITIES[4], 1000) payload.add_signer(IDENTITIES[0]) payload.charge_rate = 1000 payload.charge_limit = 1000000 payload.valid_from = 100 payload.valid_until = 200 # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(tx, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def de_stake(self, entity: Entity, amount: int, fee: int): """ Destakes a specific amount of tokens from a staking miner. This will put the tokens in a cool down period :param entity: The entity object that desires to destake :param amount: The amount of tokens to destake :return: The digest of the submitted transaction :raises: ApiError on any failures """ ENDPOINT = 'deStake' tx = TokenTxFactory.de_stake(entity, amount, fee, [entity]) self._set_validity_period(tx) tx.sign(entity) # encode and sign the transaction encoded_tx = transaction.encode_transaction(tx) # submit the transaction return self._post_tx_json(encoded_tx, ENDPOINT)
def transfer(self, entity: Entity, to: AddressLike, amount: int, fee: int): """ Transfers funds from one account to another account :param entity: The entity from which to transfer funds :param to: The bytes of the targeted address to send funds to :param amount: The amount of funds being transfered :param fee: The fee associated with the transfer :return: The digest of the submitted transaction :raises: ApiError on any failures """ ENDPOINT = 'transfer' tx = TokenTxFactory.transfer(entity, to, amount, fee, [entity]) self._set_validity_period(tx) tx.sign(entity) # encode and sign the transaction encoded_tx = transaction.encode_transaction(tx) # submit the transaction return self._post_tx_json(encoded_tx, ENDPOINT)
def test_synergetic_data_submission(self): EXPECTED_DIGEST = "261ba516c9b7b4d3ecb39f349dbb0a35db0d9fc362f2b9cc81c7d844be4d0081" EXPECTED_PAYLOAD = \ "a160c000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d4c1271001c3000000e8d4" \ "a5100080e6672a9d98da667e5dc25b2bca8acf9644a7ac0797f01cb5968abf39de011df204646174610f7b227661" \ "6c7565223a20313233347d00000000000000000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4f" \ "dffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c" # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.valid_until = 10000 payload.target_synergetic_data(Address(IDENTITIES[4]), BitVector()) payload.charge_rate = 1 payload.charge_limit = 1000000000000 payload.action = 'data' payload.data = json.dumps({'value': 1234}).encode('ascii') payload.add_signer(IDENTITIES[0]) # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def test_chain_code(self): EXPECTED_DIGEST = "25cc72ca7d4871aaaabd027af129ecd4327adde5ec0c9977bfe11018d4bab64a" EXPECTED_PAYLOAD = \ "a1608000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \ "0b666f6f2e6261722e62617a066c61756e636802676f00000000000000000418c2a33af8bd2cba7fa714a840a308" \ "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \ "a0251c" # build the payload bytes for the transaction with mock.patch('random.getrandbits') as mock_counter: mock_counter.side_effect = [0] payload = Transaction() payload.from_address = IDENTITIES[0] payload.add_signer(IDENTITIES[0]) payload.charge_rate = 1000 payload.charge_limit = 1000000 payload.target_chain_code('foo.bar.baz', BitVector()) payload.action = 'launch' payload.data = 'go'.encode('ascii') # sign the final transaction payload.sign(ENTITIES[0]) transaction_bytes = transaction.encode_transaction(payload) self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD) # attempt to decode a transaction from the generated bytes buffer = io.BytesIO(transaction_bytes) success, tx = transaction.decode_transaction(buffer) self.assertTrue(success) self.assertTxAreEqual(payload, tx) # Check payload digest self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
def encode(self) -> Optional[bytes]: if self.is_incomplete: return None else: return transaction.encode_transaction(self)
def encode_partial(self) -> bytes: return transaction.encode_transaction(self)
def run_transfer(args): address_book = AddressBook() key_store = KeyStore() # choose the destination if args.destination in address_book.keys(): destination = address_book.lookup_address(args.destination) else: destination = key_store.lookup_address(args.destination) if destination is None: destination = Address(args.destination) # change the amount amount = args.amount * 10000000000 # check all the signers make sense for signer in args.signers: if signer not in key_store.list_keys(): raise RuntimeError('Unknown key: {}'.format(signer)) # determine the from account from_address_name = None if len(args.signers) == 1 and args.from_address is None: from_address_name = args.signers[0] elif len(args.signers) >= 1 and args.from_address is not None: present = args.from_address in key_store.list_keys( ) or args.from_address in address_book.keys() from_address_name = args.from_address if not present: raise RuntimeError('Unknown from address: {}'.format( args.from_address)) else: raise RuntimeError('Unable to determine from account') print('Network....:', args.network) print('From.......:', str(from_address_name)) print('Signers....:', args.signers) print('Destination:', str(destination)) print('Amount.....:', args.amount, 'FET') print() input('Press enter to continue') api = create_api(args.network) # start unsealing the private keys entities = {} for signer in args.signers: entity = key_store.load_key( signer, getpass.getpass('Enter password for key {}: '.format(signer))) entities[signer] = entity from_address = None if from_address_name in entities: from_address = Address(entities[from_address_name]) elif from_address_name in address_book.keys(): from_address = Address(address_book.lookup_address(from_address_name)) # build up the basic transaction information tx = api.tokens._create_skeleton_tx(len(entities.values())) tx.from_address = Address(from_address) tx.add_transfer(destination, amount) for entity in entities.values(): tx.add_signer(entity) # encode and sign the transaction encoded_tx = encode_transaction(tx, list(entities.values())) # # submit the transaction print('Submitting TX...') api.sync(api.tokens._post_tx_json(encoded_tx, 'transfer')) print('Submitting TX...complete')