def test_transaction_duplicate_keys(self): payer, program = generate_keys(2) keys = generate_keys(4) data = bytes([1, 2, 3]) # Key[0]: ReadOnlySigner -> WritableSigner # Key[1]: ReadOnly -> ReadOnlySigner # Key[2]: Writable -> Writable (ReadOnly,noop) # Key[3]: WritableSigner -> WritableSigner (ReadOnly,noop) tx = Transaction.new( payer.public_key, [ Instruction( program.public_key, data, [ AccountMeta.new_read_only(keys[0].public_key, True), # 0 ReadOnlySigner AccountMeta.new_read_only(keys[1].public_key, False), # 1 ReadOnly AccountMeta.new(keys[2].public_key, False), # Writable AccountMeta.new(keys[3].public_key, True), # WritableSigner # Upgrade keys [0] and [1] AccountMeta.new(keys[0].public_key, False), # Writable (promote to WritableSigner) AccountMeta.new_read_only(keys[1].public_key, True), # Signer (promote to ReadOnlySigner) # 'Downgrade' keys [2] and [3] (should be noop) AccountMeta.new_read_only(keys[2].public_key, False), # ReadOnly; still Writable AccountMeta.new_read_only(keys[3].public_key, False) # Readonly; still a WritableSigner ], ), ] ) # Intentionally sign out of order to ensure ordering is fixed tx.sign([keys[0], keys[1], keys[3], payer]) assert len(tx.signatures) == 4 assert len(tx.message.accounts) == 6 assert tx.message.header.num_signatures == 3 assert tx.message.header.num_read_only_signed == 1 assert tx.message.header.num_read_only == 1 message = tx.message.marshal() for idx, key in enumerate([payer, keys[0], keys[3], keys[1]]): assert key.public_key.verify(message, tx.signatures[idx]) expected_keys = [payer, keys[0], keys[3], keys[1], keys[2], program] for idx, account in enumerate(expected_keys): assert tx.message.accounts[idx] == account.public_key assert tx.message.instructions[0].program_index == 5 assert tx.message.instructions[0].data == data assert tx.message.instructions[0].accounts == bytes([1, 3, 4, 2, 1, 3, 4, 2])
def _generate_tx(with_il: Optional[bool] = False) -> Tuple[solana.Transaction, Optional[model_pb2.InvoiceList]]: il = None instructions = [] if with_il: il = model_pb2.InvoiceList( invoices=[ model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='title1', description='desc1', amount=50, sku=b'somesku') ] ) ] ) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.P2P, 0, fk) instructions.append(solana.memo_instruction(base64.b64encode(memo.val).decode('utf-8'))) keys = [key.public_key for key in generate_keys(3)] instructions.append(solana.transfer( keys[0], keys[1], keys[2], 20, ), ) return solana.Transaction.new( _SIGNING_KEY.public_key, instructions ), il
def test_create_associated_account(self): keys = [key.public_key for key in generate_keys(3)] expected_addr = get_associated_account(keys[1], keys[2]) instruction, addr = create_associated_token_account( keys[0], keys[1], keys[2]) assert addr == expected_addr assert len(instruction.data) == 0 assert len(instruction.accounts) == 7 assert instruction.accounts[0].is_signer assert instruction.accounts[0].is_writable assert not instruction.accounts[1].is_signer assert instruction.accounts[1].is_writable for i in range(2, len(instruction.accounts)): assert not instruction.accounts[i].is_signer assert not instruction.accounts[i].is_writable assert instruction.accounts[4].public_key == system.PROGRAM_KEY assert instruction.accounts[5].public_key == PROGRAM_KEY assert instruction.accounts[6].public_key == system.RENT_SYS_VAR tx = Transaction.unmarshal( Transaction.new(keys[0], [instruction]).marshal()) decompiled = decompile_create_associated_account(tx.message, 0) assert decompiled.subsidizer == keys[0] assert decompiled.owner == keys[1] assert decompiled.mint == keys[2]
def test_errors_from_solana_tx(self, instruction_index, exp_op_index, exp_payment_index): keys = [pk.public_key for pk in generate_keys(4)] tx = solana.Transaction.new( keys[0], [ memo.memo_instruction('data'), token.transfer(keys[1], keys[2], keys[1], 100), token.set_authority(keys[1], keys[1], token.AuthorityType.CLOSE_ACCOUNT, keys[3]) ] ) tx_id = b'tx_sig' errors = TransactionErrors.from_solana_tx(tx, model_pbv4.TransactionError( reason=model_pbv4.TransactionError.Reason.INSUFFICIENT_FUNDS, instruction_index=instruction_index, ), tx_id) assert isinstance(errors.tx_error, InsufficientBalanceError) assert len(errors.op_errors) == 3 for i in range(0, len(errors.op_errors)): if i == exp_op_index: assert isinstance(errors.op_errors[i], InsufficientBalanceError) else: assert not errors.op_errors[i] if exp_payment_index > -1: assert len(errors.payment_errors) == 1 for i in range(0, len(errors.payment_errors)): if i == exp_payment_index: assert isinstance(errors.payment_errors[i], InsufficientBalanceError) else: assert not errors.payment_errors[i] else: assert not errors.payment_errors
def test_transaction_invalid_accounts(self): keys = generate_keys(2) tx = Transaction.new( keys[0].public_key, [Instruction( keys[1].public_key, bytes([1, 2, 3]), [ AccountMeta.new(keys[0].public_key, True) ], )], ) tx.message.instructions[0].program_index = 2 # invalid index with pytest.raises(ValueError): Transaction.unmarshal(tx.marshal()) tx = Transaction.new( keys[0].public_key, [Instruction( keys[1].public_key, bytes([1, 2, 3]), [ AccountMeta.new(keys[0].public_key, True) ], )], ) tx.message.instructions[0].accounts = bytes([2]) # invalid index with pytest.raises(ValueError): Transaction.unmarshal(tx.marshal())
def test_create_without_account_holder_auth(self): keys = [priv.public_key for priv in generate_keys(3)] create_instructions, addr = self._generate_create(keys[0], keys[1], keys[2]) create_assoc_instruction, assoc = token.create_associated_token_account(keys[0], keys[1], keys[2]) txs = [ solana.Transaction.new( keys[0], create_instructions[:3], ), solana.Transaction.new( keys[0], [ create_assoc_instruction, token.set_authority(assoc, assoc, token.AuthorityType.CLOSE_ACCOUNT, new_authority=keys[0]), ] ) ] for idx, tx in enumerate(txs): creations, payments = parse_transaction(tx) assert len(creations) == 1 assert len(payments) == 0 if idx == 0: # Randomly generated in _generate_create assert creations[0].owner assert creations[0].address == addr else: assert creations[0].owner == keys[1] assert creations[0].address == assoc
def test_from_json(self): memo = AgoraMemo.new(1, TransactionType.P2P, 0, b'somefk') keys = [key.public_key for key in generate_keys(4)] token_program = keys[3] tx = solana.Transaction.new(keys[0], [ solana.memo_instruction( base64.b64encode(memo.val).decode('utf-8')), solana.transfer( keys[1], keys[2], keys[3], 20, token_program, ), ]) data = { 'transaction': base64.b64encode(tx.marshal()).decode('utf-8'), 'transaction_error': 'unauthorized', 'transaction_error_raw': 'raw_error' } solana_event = SolanaEvent.from_json(data) assert solana_event.transaction == tx assert isinstance(solana_event.tx_error, InvalidSignatureError) assert solana_event.tx_error_raw == 'raw_error'
def test_payments_from_transaction_with_invoice_list(self): il = model_pb2.InvoiceList(invoices=[ model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='t1', amount=10), ] ), model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='t1', amount=15), ] ), ]) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.P2P, 0, fk) keys = [key.public_key for key in generate_keys(5)] token_program = keys[4] tx = solana.Transaction.new( keys[0], [ solana.memo_instruction(base64.b64encode(memo.val).decode('utf-8')), solana.transfer( keys[1], keys[2], keys[3], 20, token_program, ), solana.transfer( keys[2], keys[3], keys[1], 40, token_program, ), ] ) payments = ReadOnlyPayment.payments_from_transaction(tx, il) assert len(payments) == 2 assert payments[0].sender == keys[1] assert payments[0].destination == keys[2] assert payments[0].tx_type == TransactionType.P2P assert payments[0].quarks == 20 assert payments[0].invoice == Invoice.from_proto(il.invoices[0]) assert not payments[0].memo assert payments[1].sender == keys[2] assert payments[1].destination == keys[3] assert payments[1].tx_type == TransactionType.P2P assert payments[1].quarks == 40 assert payments[1].invoice == Invoice.from_proto(il.invoices[1]) assert not payments[1].memo
def _generate_create_tx() -> Tuple[solana.Transaction, PublicKey, PublicKey]: keys = [key.public_key for key in generate_keys(2)] create_assoc_instruction, assoc = token.create_associated_token_account( _SIGNING_KEY.public_key, keys[0], keys[1]) return solana.Transaction.new(_SIGNING_KEY.public_key, [ create_assoc_instruction, token.set_authority(assoc, assoc, token.AuthorityType.CLOSE_ACCOUNT, new_authority=_SIGNING_KEY.public_key), ]), keys[0], assoc
def test_from_json_full_kin_4(self): memo = AgoraMemo.new(1, TransactionType.P2P, 0, b'somefk') keys = [key.public_key for key in generate_keys(4)] token_program = keys[3] tx = solana.Transaction.new(keys[0], [ solana.memo_instruction( base64.b64encode(memo.val).decode('utf-8')), solana.transfer( keys[1], keys[2], keys[3], 20, token_program, ), ]) il = model_pb2.InvoiceList(invoices=[ model_pb2.Invoice(items=[ model_pb2.Invoice.LineItem(title='title1', description='desc1', amount=50, sku=b'somesku') ]) ]) data = { 'kin_version': 4, 'tx_id': base64.b64encode(b'txsig'), 'invoice_list': il.SerializeToString(), 'solana_event': { 'transaction': base64.b64encode(tx.marshal()).decode('utf-8'), 'transaction_error': 'bad_nonce', 'transaction_error_raw': 'raw_error', } } event = TransactionEvent.from_json(data) assert event.kin_version == 4 assert event.tx_id == b'txsig' assert len(event.invoice_list.invoices) == 1 assert len(event.invoice_list.invoices[0].items) == 1 line_item = event.invoice_list.invoices[0].items[0] assert line_item.title == 'title1' assert line_item.description == 'desc1' assert line_item.amount == 50 assert line_item.sku == b'somesku' assert not event.stellar_event assert event.solana_event.transaction == tx assert isinstance(event.solana_event.tx_error, BadNonceError) assert event.solana_event.tx_error_raw == 'raw_error'
def test_transaction_single_instruction(self): payer, program = generate_keys(2) keys = generate_keys(4) data = bytes([1, 2, 3]) tx = Transaction.new( payer.public_key, [Instruction( program.public_key, data, [ AccountMeta.new_read_only(keys[0].public_key, True), AccountMeta.new_read_only(keys[1].public_key, False), AccountMeta.new(keys[2].public_key, False), AccountMeta.new(keys[3].public_key, True), ], )], ) tx.sign([keys[0], keys[3], payer]) assert len(tx.signatures) == 3 assert len(tx.message.accounts) == 6 assert tx.message.header.num_signatures == 2 assert tx.message.header.num_read_only_signed == 1 assert tx.message.header.num_read_only == 2 message = tx.message.marshal() assert payer.public_key.verify(message, tx.signatures[0]) assert keys[3].public_key.verify(message, tx.signatures[1]) assert keys[0].public_key.verify(message, tx.signatures[2]) expected_keys = [payer, keys[3], keys[0], keys[2], keys[1], program] for idx, key in enumerate(expected_keys): assert tx.message.accounts[idx] == key.public_key assert tx.message.instructions[0].program_index == 5 assert tx.message.instructions[0].data == data assert tx.message.instructions[0].accounts == bytes([2, 4, 3, 1])
def test_transfers_with_invoices(self): keys = [priv.public_key for priv in generate_keys(5)] # Single memo memo_instruction, il = self._get_invoice_memo_instruction(TransactionType.SPEND, 10, 2) tx = solana.Transaction.new( keys[0], [ memo_instruction, token.transfer(keys[1], keys[2], keys[3], 10), token.transfer(keys[2], keys[3], keys[4], 20) ], ) creations, payments = parse_transaction(tx, il) assert len(creations) == 0 for i in range(2): assert payments[i].sender == keys[1 + i] assert payments[i].destination == keys[2 + i] assert payments[i].tx_type == TransactionType.SPEND assert payments[i].quarks == (1 + i) * 10 assert payments[i].invoice == Invoice.from_proto(il.invoices[i]) assert not payments[i].memo # Multiple memos memo_instruction_1, il1 = self._get_invoice_memo_instruction(TransactionType.SPEND, 10, 1) memo_instruction_2, il2 = self._get_invoice_memo_instruction(TransactionType.P2P, 10, 1) tx = solana.Transaction.new( keys[0], [ memo_instruction_1, token.transfer(keys[1], keys[2], keys[3], 10), memo_instruction_2, token.transfer(keys[2], keys[3], keys[4], 20), ], ) creations, payments = parse_transaction(tx, il1) assert len(creations) == 0 expected_invoices = [il1.invoices[0], None] expected_types = [TransactionType.SPEND, TransactionType.P2P] for i in range(2): assert payments[i].sender == keys[1 + i] assert payments[i].destination == keys[2 + i] assert payments[i].tx_type == expected_types[i] assert payments[i].quarks == (1 + i) * 10 if expected_invoices[i]: assert payments[i].invoice == Invoice.from_proto(expected_invoices[i]) else: assert not payments[i].invoice assert not payments[i].memo
def test_get_transaction(self, grpc_channel, executor, no_retry_client): source, dest = [key.public_key for key in generate_keys(2)] transaction_id = b'someid' future = executor.submit(no_retry_client.get_transaction, transaction_id) agora_memo = AgoraMemo.new(1, TransactionType.SPEND, 0, b'') tx = Transaction.new(PrivateKey.random().public_key, [ memo.memo_instruction( base64.b64encode(agora_memo.val).decode('utf-8')), token.transfer(source, dest, PrivateKey.random().public_key, 100), ]) resp = tx_pb_v4.GetTransactionResponse( state=tx_pb_v4.GetTransactionResponse.State.SUCCESS, item=tx_pb_v4.HistoryItem( transaction_id=model_pb_v4.TransactionId( value=transaction_id, ), solana_transaction=model_pb_v4.Transaction( value=tx.marshal(), ), payments=[ tx_pb_v4.HistoryItem.Payment( source=model_pb_v4.SolanaAccountId(value=source.raw), destination=model_pb_v4.SolanaAccountId( value=dest.raw), amount=100, ) ], invoice_list=model_pb_v3.InvoiceList(invoices=[ model_pb_v3.Invoice(items=[ model_pb_v3.Invoice.LineItem(title='t1', amount=15), ]), ])), ) req = self._set_get_transaction_resp(grpc_channel, resp) assert req.transaction_id.value == transaction_id tx_data = future.result() assert tx_data.tx_id == transaction_id assert tx_data.transaction_state == TransactionState.SUCCESS assert len(tx_data.payments) == 1 assert not tx_data.error p = tx_data.payments[0] assert p.sender.raw == source.raw assert p.destination.raw == dest.raw assert p.tx_type == TransactionType.SPEND assert p.quarks == 100 assert p.invoice.to_proto().SerializeToString( ) == resp.item.invoice_list.invoices[0].SerializeToString() assert not p.memo
def test_transaction_missing_blockhash(self): payer, program = generate_keys(2) tx = Transaction.new( payer.public_key, [Instruction( program.public_key, bytes([1, 2, 3]), [ AccountMeta.new(payer.public_key, True), ], )], ) assert Transaction.unmarshal(tx.marshal()) == tx
def test_initialize_account(self): public_keys = [key.public_key for key in generate_keys(3)] instruction = initialize_account(public_keys[0], public_keys[1], public_keys[2], _token_program) assert instruction.data == bytes([Command.INITIALIZE_ACCOUNT]) assert instruction.accounts[0].is_signer assert instruction.accounts[0].is_writable for i in range(1, 4): assert not instruction.accounts[i].is_signer assert not instruction.accounts[i].is_writable tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal()) decompiled = decompile_initialize_account(tx.message, 0, _token_program) assert decompiled.account == public_keys[0] assert decompiled.mint == public_keys[1] assert decompiled.owner == public_keys[2]
def test_from_json_invalid(self): with pytest.raises(ValueError) as e: CreateAccountRequest.from_json({}) assert 'solana_transaction' in str(e) keys = [key.public_key for key in generate_keys(4)] tx = solana.Transaction.new(keys[0], [ token.transfer( keys[1], keys[2], keys[3], 20, ), ]) with pytest.raises(ValueError) as e: CreateAccountRequest.from_json( {'solana_transaction': base64.b64encode(tx.marshal())}) assert 'unexpected payments' in str(e) tx = solana.Transaction.new(keys[0], []) with pytest.raises(ValueError) as e: CreateAccountRequest.from_json( {'solana_transaction': base64.b64encode(tx.marshal())}) assert 'expected exactly 1 creation' in str(e) create_assoc_instruction1, assoc1 = token.create_associated_token_account( keys[0], keys[1], keys[2]) create_assoc_instruction2, assoc2 = token.create_associated_token_account( keys[0], keys[1], keys[2]) tx = solana.Transaction.new(keys[0], [ create_assoc_instruction1, token.set_authority(assoc1, assoc1, token.AuthorityType.CLOSE_ACCOUNT, new_authority=keys[0]), create_assoc_instruction2, token.set_authority(assoc2, assoc2, token.AuthorityType.CLOSE_ACCOUNT, new_authority=keys[0]), ]) with pytest.raises(ValueError) as e: CreateAccountRequest.from_json( {'solana_transaction': base64.b64encode(tx.marshal())}) assert 'expected exactly 1 creation' in str(e)
def test_with_invalid_instructions(self): keys = [priv.public_key for priv in generate_keys(5)] invalid_instructions = [ token.set_authority(keys[1], keys[2], AuthorityType.ACCOUNT_HOLDER, new_authority=keys[3]), token.initialize_account(keys[1], keys[2], keys[3]), system.create_account(keys[1], keys[2], keys[3], 10, 10), ] for i in invalid_instructions: tx = solana.Transaction.new( keys[0], [ token.transfer(keys[1], keys[2], keys[3], 10), i, ] ) with pytest.raises(ValueError): parse_transaction(tx)
def test_from_json_kin_4(self): il = model_pb2.InvoiceList( invoices=[ model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='title1', description='desc1', amount=50, sku=b'somesku') ] ) ] ) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.P2P, 0, fk) keys = [key.public_key for key in generate_keys(4)] token_program = keys[3] tx = solana.Transaction.new( keys[0], [ solana.memo_instruction(base64.b64encode(memo.val).decode('utf-8')), solana.transfer( keys[1], keys[2], keys[3], 20, token_program, ), ] ) data = { 'kin_version': 4, 'solana_transaction': base64.b64encode(tx.marshal()), 'invoice_list': base64.b64encode(il.SerializeToString()), } req = SignTransactionRequest.from_json(data, Environment.TEST) assert len(req.payments) == 1 assert req.payments[0].invoice == Invoice.from_proto(il.invoices[0]) assert req.kin_version == data['kin_version'] assert req.transaction == tx
def test_transfers_no_invoices(self): keys = [priv.public_key for priv in generate_keys(5)] tx = solana.Transaction.new( keys[0], [ token.transfer(keys[1], keys[2], keys[3], 10), token.transfer(keys[2], keys[3], keys[4], 20), ], ) creations, payments = parse_transaction(tx) assert len(creations) == 0 for i in range(2): assert payments[i].sender == keys[1 + i] assert payments[i].destination == keys[2 + i] assert payments[i].tx_type == TransactionType.UNKNOWN assert payments[i].quarks == (1 + i) * 10 assert not payments[i].invoice assert not payments[i].memo
def test_all(self, grpc_channel, executor): resolver = TokenAccountResolver( account_stub=account_pb_grpc.AccountStub(grpc_channel)) owner, token1, token2 = [key.public_key for key in generate_keys(3)] future = executor.submit(resolver.resolve_token_accounts, owner) md, request, rpc = grpc_channel.take_unary_unary( account_pb.DESCRIPTOR.services_by_name['Account']. methods_by_name['ResolveTokenAccounts']) rpc.terminate( account_pb.ResolveTokenAccountsResponse(token_accounts=[ model_pb.SolanaAccountId(value=key.raw) for key in [token1, token2] ]), (), grpc.StatusCode.OK, '') assert future.result() == [token1, token2] # ensure it's cached assert resolver.resolve_token_accounts(owner) == [token1, token2]
def test_create_account(self): public_keys = [key.public_key for key in generate_keys(3)] instruction = create_account(public_keys[0], public_keys[1], public_keys[2], 12345, 67890) assert len(instruction.data) == 52 assert instruction.data[0:4] == Command.CREATE_ACCOUNT.to_bytes( 4, 'little') assert instruction.data[4:12] == (12345).to_bytes(8, 'little') assert instruction.data[12:20] == (67890).to_bytes(8, 'little') assert instruction.data[20:] == public_keys[2].raw tx = Transaction.unmarshal( Transaction.new(public_keys[0], [instruction]).marshal()) decompiled = decompile_create_account(tx.message, 0) assert decompiled.funder == public_keys[0] assert decompiled.address == public_keys[1] assert decompiled.owner == public_keys[2] assert decompiled.lamports == 12345 assert decompiled.size == 67890
def test_transfer(self): public_keys = [key.public_key for key in generate_keys(3)] instruction = transfer(public_keys[0], public_keys[1], public_keys[2], 123456789, _token_program) assert instruction.data[0] == Command.TRANSFER assert instruction.data[1:] == (123456789).to_bytes(8, 'little') assert not instruction.accounts[0].is_signer assert instruction.accounts[0].is_writable assert not instruction.accounts[1].is_signer assert instruction.accounts[1].is_writable assert instruction.accounts[2].is_signer assert instruction.accounts[2].is_writable tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal()) decompiled = decompile_transfer(tx.message, 0, _token_program) assert decompiled.source == public_keys[0] assert decompiled.dest == public_keys[1] assert decompiled.owner == public_keys[2] assert decompiled.amount == 123456789
def test_payments_from_transaction(self): keys = [key.public_key for key in generate_keys(5)] token_program = keys[4] tx = solana.Transaction.new( keys[0], [ solana.memo_instruction('somememo'), solana.transfer( keys[1], keys[2], keys[3], 20, token_program, ), solana.transfer( keys[2], keys[3], keys[1], 40, token_program, ), ] ) payments = ReadOnlyPayment.payments_from_transaction(tx) assert len(payments) == 2 assert payments[0].sender == keys[1] assert payments[0].destination == keys[2] assert payments[0].tx_type == TransactionType.UNKNOWN assert payments[0].quarks == 20 assert not payments[0].invoice assert payments[0].memo == 'somememo' assert payments[1].sender == keys[2] assert payments[1].destination == keys[3] assert payments[1].tx_type == TransactionType.UNKNOWN assert payments[1].quarks == 40 assert not payments[1].invoice assert payments[1].memo == 'somememo'
def test_create_without_close_authority(self): keys = [priv.public_key for priv in generate_keys(3)] create_instructions, addr = self._generate_create(keys[0], keys[1], keys[2]) create_assoc_instruction, assoc = token.create_associated_token_account(keys[0], keys[1], keys[2]) txs = [ solana.Transaction.new( keys[0], create_instructions[:2], ), solana.Transaction.new( keys[0], [ create_assoc_instruction, ], ) ] for tx in txs: with pytest.raises(ValueError) as e: parse_transaction(tx) assert 'SetAuthority(Close)' in str(e)
def test_get_tx_id(self): envelope = _generate_envelope() data = { 'kin_version': 3, 'envelope_xdr': envelope.xdr(), } req = SignTransactionRequest.from_json(data, Environment.TEST) assert req.get_tx_id() == envelope.hash_meta() envelope = _generate_kin_2_envelope() data = { 'kin_version': 2, 'envelope_xdr': envelope.xdr(), } req = SignTransactionRequest.from_json(data, Environment.TEST) assert req.get_tx_id() == envelope.hash_meta() keys = generate_keys(4) public_keys = [key.public_key for key in keys] token_program = public_keys[3] tx = solana.Transaction.new( public_keys[0], [ solana.transfer( public_keys[1], public_keys[2], public_keys[3], 20, token_program, ), ] ) tx.sign([keys[0]]) req = SignTransactionRequest.from_json(data, Environment.TEST) assert req.get_tx_hash() == envelope.hash_meta()
def test_payments_from_transaction_invalid(self): il = model_pb2.InvoiceList(invoices=[ model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='t1', amount=10), ] ), ]) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.P2P, 0, fk) keys = [key.public_key for key in generate_keys(5)] token_program = keys[4] tx = solana.Transaction.new( keys[0], [ solana.memo_instruction(base64.b64encode(memo.val).decode('utf-8')), solana.transfer( keys[1], keys[2], keys[3], 20, token_program, ), solana.transfer( keys[2], keys[3], keys[1], 40, token_program, ), ] ) # mismatching number of invoices and instructions with pytest.raises(ValueError): ReadOnlyPayment.payments_from_transaction(tx, il)
def test_set_authority(self): public_keys = [key.public_key for key in generate_keys(3)] # With no new authority instruction = set_authority(public_keys[0], public_keys[1], AuthorityType.AccountHolder, _token_program) assert instruction.data[0] == Command.SET_AUTHORITY assert instruction.data[1] == AuthorityType.AccountHolder assert instruction.data[2] == 0 tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal()) decompiled = decompile_set_authority(tx.message, 0, _token_program) assert decompiled.account == public_keys[0] assert decompiled.current_authority == public_keys[1] assert decompiled.authority_type == AuthorityType.AccountHolder assert not decompiled.new_authority # With new authority instruction = set_authority(public_keys[0], public_keys[1], AuthorityType.CloseAccount, _token_program, new_authority=public_keys[2]) assert instruction.data[0] == Command.SET_AUTHORITY assert instruction.data[1] == AuthorityType.CloseAccount assert instruction.data[2] == 1 assert instruction.data[3:] == public_keys[2].raw assert not instruction.accounts[0].is_signer assert instruction.accounts[0].is_writable assert instruction.accounts[1].is_signer assert not instruction.accounts[1].is_writable tx = Transaction.unmarshal(Transaction.new(public_keys[0], [instruction]).marshal()) decompiled = decompile_set_authority(tx.message, 0, _token_program) assert decompiled.account == public_keys[0] assert decompiled.current_authority == public_keys[1] assert decompiled.authority_type == AuthorityType.CloseAccount assert decompiled.new_authority == public_keys[2]
def test_from_proto_solana_text_memo(self): source, dest, token_program = [ key.public_key for key in generate_keys(3) ] tx = Transaction.new(PrivateKey.random().public_key, [ memo_instruction('somememo'), transfer(source, dest, PrivateKey.random().public_key, 20), ]) history_item = tx_pb.HistoryItem( transaction_id=model_pb.TransactionId(value=b'somehash'), cursor=tx_pb.Cursor(value=b'cursor1'), solana_transaction=model_pb.Transaction(value=tx.marshal(), ), payments=[ tx_pb.HistoryItem.Payment( source=model_pb.SolanaAccountId(value=source.raw), destination=model_pb.SolanaAccountId(value=dest.raw), amount=20, ), ], ) data = TransactionData.from_proto( history_item, tx_pb.GetTransactionResponse.State.SUCCESS) assert data.tx_id == b'somehash' assert data.transaction_state == TransactionState.SUCCESS assert len(data.payments) == 1 payment = data.payments[0] assert payment.sender.raw == source.raw assert payment.destination.raw == dest.raw assert payment.tx_type == TransactionType.UNKNOWN assert payment.quarks == 20 assert not payment.invoice assert payment.memo == 'somememo'
def test_from_json_with_tx_event(self): keys = [key.public_key for key in generate_keys(3)] tx = solana.Transaction.new( keys[0], [ solana.transfer( keys[1], keys[1], keys[2], 20, ), ] ) event = Event.from_json({ 'transaction_event': { 'tx_id': base64.b64encode(b'txsig'), 'solana_event': { 'transaction': base64.b64encode(tx.marshal()).decode('utf-8'), } } }) assert event.transaction_event.tx_id == b'txsig' assert event.transaction_event.solana_event
def test_no_accounts(self, grpc_channel, executor): resolver = TokenAccountResolver( account_stub=account_pb_grpc.AccountStub(grpc_channel)) account = generate_keys(1)[0].public_key future = executor.submit(resolver.resolve_token_accounts, account) md, request, rpc = grpc_channel.take_unary_unary( account_pb.DESCRIPTOR.services_by_name['Account']. methods_by_name['ResolveTokenAccounts']) rpc.terminate(account_pb.ResolveTokenAccountsResponse(), (), grpc.StatusCode.OK, '') assert future.result() == [] # ensure not cached future = executor.submit(resolver.resolve_token_accounts, account) md, request, rpc = grpc_channel.take_unary_unary( account_pb.DESCRIPTOR.services_by_name['Account']. methods_by_name['ResolveTokenAccounts']) rpc.terminate(account_pb.ResolveTokenAccountsResponse(), (), grpc.StatusCode.OK, '') assert future.result() == []