Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add submit and wait for transaction submission #528

Merged
merged 43 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d8e364c
add submit and wait
pdp2121 Feb 21, 2023
6d1ed3e
add tests and fix errors
pdp2121 Feb 22, 2023
328d9c9
fix snippets
pdp2121 Feb 24, 2023
d5c7419
support signed tx
pdp2121 Mar 2, 2023
f4c4176
Merge branch 'master' into add-submit-and-wait
pdp2121 Mar 2, 2023
022ead1
fix is_signed
pdp2121 Mar 2, 2023
5d4a0e0
update docs
pdp2121 Mar 3, 2023
e5132d3
add missing variable
pdp2121 Mar 3, 2023
5b0bb76
support blob
pdp2121 Mar 8, 2023
9276025
fix optional
pdp2121 Mar 8, 2023
bd399eb
increase ledger accept delay
pdp2121 Mar 9, 2023
214e298
Update snippets/multisign.py
pdp2121 Mar 20, 2023
5997c46
Update snippets/reliable_transaction_submission.py
pdp2121 Mar 20, 2023
7644c13
small updates
pdp2121 Mar 20, 2023
1141a8e
small doc fix
pdp2121 Mar 20, 2023
b08c19d
add positional args
pdp2121 Mar 20, 2023
6772a82
Merge branch 'master' into add-submit-and-wait
pdp2121 Mar 20, 2023
bf82159
Update snippets/multisign.py
pdp2121 Mar 22, 2023
0570613
test remove from dict
pdp2121 Mar 31, 2023
5a705f8
Merge branch 'add-submit-and-wait' of https://github.com/pdp2121/xrpl…
pdp2121 Mar 31, 2023
da1ac1c
Update xrpl/asyncio/transaction/reliable_submission.py
pdp2121 Mar 31, 2023
fe79767
remove predefined sequence
pdp2121 Mar 31, 2023
81125ee
Merge branch 'add-submit-and-wait' of https://github.com/pdp2121/xrpl…
pdp2121 Mar 31, 2023
ce51eec
Merge branch 'XRPLF:master' into add-submit-and-wait
pdp2121 Mar 31, 2023
05f20b0
add fail hard param
pdp2121 Mar 31, 2023
2b44c4b
fix for multisign
pdp2121 Mar 31, 2023
9634e8b
move is_signed to tx
pdp2121 Apr 11, 2023
7e6ef17
add changelog
pdp2121 Apr 11, 2023
8148a62
Merge branch 'master' into add-submit-and-wait
pdp2121 Apr 11, 2023
ef66a49
update changelog in unreleased
pdp2121 Apr 12, 2023
ec73e5f
Merge branch 'master' into add-submit-and-wait
pdp2121 Apr 12, 2023
3e15002
Update CHANGELOG.md
pdp2121 May 5, 2023
4d4f210
fix multisign condition
pdp2121 May 5, 2023
0c3ae7d
Merge branch 'add-submit-and-wait' of https://github.com/pdp2121/xrpl…
pdp2121 May 5, 2023
072ea83
Update xrpl/asyncio/transaction/reliable_submission.py
pdp2121 May 5, 2023
f5af074
docs fix for wallet variable
pdp2121 May 8, 2023
20ae956
Merge branch 'add-submit-and-wait' of https://github.com/pdp2121/xrpl…
pdp2121 May 8, 2023
d42e070
update fail hard docstring
pdp2121 May 9, 2023
f3f4dff
modify and add tests to is_signed
pdp2121 May 10, 2023
95bbf32
add blob methods
pdp2121 May 10, 2023
b067da2
Merge branch 'master' into add-submit-and-wait
pdp2121 May 10, 2023
51201c2
update comments
pdp2121 May 11, 2023
73d50e6
Merge branch 'add-submit-and-wait' of https://github.com/pdp2121/xrpl…
pdp2121 May 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [[Unreleased]]
### Added:
- Added `submit_and_wait` to sign (if needed), autofill, submit a transaction and wait for its final outcome
- `submit` and `send_reliable_submission` now accept an optional boolean param `fail_hard` (if `True` halt the submission if it's not immediately validated)

### Fixed:
- Refactored `does_account_exist` and `get_balance` to avoid deprecated methods and use `ledger_index` parameter

Expand Down
27 changes: 11 additions & 16 deletions snippets/multisign.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
"""Example of how we can multisign a transaction"""
from xrpl.clients import JsonRpcClient
from xrpl.models.requests import SubmitMultisigned
from xrpl.models.transactions import AccountSet, SignerEntry, SignerListSet
from xrpl.transaction import (
autofill,
autofill_and_sign,
multisign,
send_reliable_submission,
sign,
)
from xrpl.transaction import autofill, multisign, sign, submit_and_wait
from xrpl.utils import str_to_hex
from xrpl.wallet import generate_faucet_wallet

Expand All @@ -29,12 +22,12 @@
signer_quorum=2,
signer_entries=signer_entries,
)
signed_signer_list_set_tx = autofill_and_sign(signer_list_set_tx, master_wallet, client)

print("Constructed SignerListSet and submitting it to the ledger...")
signed_list_set_tx_response = send_reliable_submission(
signed_signer_list_set_tx, client
print(
"""Constructing SignerListSet then autofilling, signing,
and submitting it to the ledger..."""
)
signed_list_set_tx_response = submit_and_wait(signer_list_set_tx, client, master_wallet)
print("SignerListSet submitted, here's the response:")
print(signed_list_set_tx_response)

Expand All @@ -57,15 +50,17 @@
print("Successfully multisigned the transaction")
print(multisigned_tx)

multisigned_tx_response = client.request(SubmitMultisigned(tx_json=multisigned_tx))
multisigned_tx_response = submit_and_wait(multisigned_tx, client)

print(multisigned_tx_response)

if multisigned_tx_response.result["engine_result"] == "tesSUCCESS":
if multisigned_tx_response.result["validated"]:
print("The multisigned transaction was accepted by the ledger:")
print(multisigned_tx_response)
if multisigned_tx_response.result["tx_json"]["Signers"]:
if multisigned_tx_response.result["Signers"]:
print(
"The transaction had "
f"{len(multisigned_tx_response.result['tx_json']['Signers'])} signatures"
f"{len(multisigned_tx_response.result['Signers'])} signatures"
)
else:
print(
Expand Down
11 changes: 4 additions & 7 deletions snippets/partial_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from xrpl.models.amounts import IssuedCurrencyAmount
from xrpl.models.requests import AccountLines
from xrpl.models.transactions import Payment, PaymentFlag, TrustSet
from xrpl.transaction import autofill_and_sign, send_reliable_submission
from xrpl.transaction import submit_and_wait
from xrpl.wallet import generate_faucet_wallet

# References
Expand All @@ -30,8 +30,7 @@
)

# Sign and autofill, then send transaction to the ledger
signed_trust_set_tx = autofill_and_sign(trust_set_tx, wallet2, client)
send_reliable_submission(signed_trust_set_tx, client)
submit_and_wait(trust_set_tx, client, wallet2)

# Both balances should be zero since nothing has been sent yet
print("Balances after trustline is claimed:")
Expand All @@ -51,8 +50,7 @@
)

# Sign and autofill, then send transaction to the ledger
signed_payment_tx = autofill_and_sign(payment_tx, wallet1, client)
payment_response = send_reliable_submission(signed_payment_tx, client)
payment_response = submit_and_wait(payment_tx, client, wallet1)
print(payment_response)

# Issuer (wallet1) should have -3840 FOO and destination (wallet2) should have 3840 FOO
Expand Down Expand Up @@ -86,8 +84,7 @@
)

# Sign and autofill, then send transaction to the ledger
signed_partial_payment_tx = autofill_and_sign(partial_payment_tx, wallet2, client)
partial_payment_response = send_reliable_submission(signed_partial_payment_tx, client)
partial_payment_response = submit_and_wait(partial_payment_tx, client, wallet2)
print(partial_payment_response)

# Tried sending 4000 of 3840 FOO -> wallet1 and wallet2 should have 0 FOO
Expand Down
9 changes: 3 additions & 6 deletions snippets/reliable_transaction_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from xrpl.clients import JsonRpcClient
from xrpl.models.requests import Tx
from xrpl.models.transactions import Payment
from xrpl.transaction import autofill_and_sign, send_reliable_submission
from xrpl.transaction import submit_and_wait
from xrpl.wallet import generate_faucet_wallet

# References:
Expand All @@ -30,11 +30,8 @@
destination=wallet2.classic_address,
)

# Sign and autofill the transaction (prepares it to be ready to submit)
signed_payment_tx = autofill_and_sign(payment_tx, wallet1, client)

# Submits transaction and waits for response (validated or rejected)
payment_response = send_reliable_submission(signed_payment_tx, client)
# Signs, autofills, and submits transaction and waits for response (validated or rejected)
payment_response = submit_and_wait(payment_tx, client, wallet1)
print("Transaction was submitted")

# Create a Transaction request to see transaction
Expand Down
8 changes: 3 additions & 5 deletions snippets/send_escrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from xrpl.clients import JsonRpcClient
from xrpl.models.requests import AccountObjects
from xrpl.models.transactions import EscrowCreate, EscrowFinish
from xrpl.transaction import autofill_and_sign, send_reliable_submission
from xrpl.transaction.reliable_submission import submit_and_wait
from xrpl.utils import datetime_to_ripple_time
from xrpl.wallet import generate_faucet_wallet

Expand Down Expand Up @@ -37,8 +37,7 @@
finish_after=finish_after,
)

signed_create_tx = autofill_and_sign(create_tx, wallet1, client)
create_escrow_response = send_reliable_submission(signed_create_tx, client)
create_escrow_response = submit_and_wait(create_tx, wallet1, client)
print(create_escrow_response)

# Create an AccountObjects request and have the client call it to see if escrow exists
Expand All @@ -55,8 +54,7 @@
offer_sequence=create_escrow_response.result["Sequence"],
)

signed_finish_tx = autofill_and_sign(finish_tx, wallet1, client)
send_reliable_submission(signed_finish_tx, client)
submit_and_wait(finish_tx, client, wallet1)

# If escrow went through successfully, 1000000 exchanged
print("Balances of wallets after Escrow was sent:")
Expand Down
8 changes: 3 additions & 5 deletions snippets/set_regular_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from xrpl.account import get_balance
from xrpl.clients import JsonRpcClient
from xrpl.models.transactions import Payment, SetRegularKey
from xrpl.transaction import autofill_and_sign, send_reliable_submission
from xrpl.transaction import submit_and_wait
from xrpl.wallet import generate_faucet_wallet

# References
Expand All @@ -28,8 +28,7 @@
account=wallet1.classic_address, regular_key=regular_key_wallet.classic_address
)

signed_tx = autofill_and_sign(tx, wallet1, client)
set_regular_key_response = send_reliable_submission(signed_tx, client)
set_regular_key_response = submit_and_wait(tx, wallet1, client)

print("Response for successful SetRegularKey tx:")
print(set_regular_key_response)
Expand All @@ -42,8 +41,7 @@
amount="1000",
)

signed_payment = autofill_and_sign(payment, regular_key_wallet, client)
payment_response = send_reliable_submission(signed_payment, client)
payment_response = submit_and_wait(payment, client, regular_key_wallet)

print("Response for tx signed using Regular Key:")
print(payment_response)
Expand Down
121 changes: 121 additions & 0 deletions tests/integration/sugar/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
autofill_and_sign,
send_reliable_submission,
sign,
submit_and_wait,
)
from xrpl.asyncio.transaction import (
submit_transaction as submit_transaction_alias_async,
)
from xrpl.clients import XRPLRequestFailureException
from xrpl.core.addresscodec import classic_address_to_xaddress
from xrpl.core.binarycodec.main import encode
from xrpl.models.exceptions import XRPLException
from xrpl.models.requests import Tx
from xrpl.models.transactions import AccountDelete, AccountSet, EscrowFinish, Payment
Expand Down Expand Up @@ -354,3 +356,122 @@ async def test_reliable_submission_no_last_ledger_sequence(self, client):
signed_payment_transaction = await sign(payment_transaction, WALLET)
with self.assertRaises(XRPLReliableSubmissionException):
await send_reliable_submission(signed_payment_transaction, client)


class TestSubmitAndWait(IntegrationTestCase):
@test_async_and_sync(
globals(),
[
"xrpl.transaction.submit_and_wait",
"xrpl.account.get_next_valid_seq_number",
"xrpl.ledger.get_fee",
],
)
async def test_submit_and_wait_simple(self, client):
account_set = AccountSet(
account=ACCOUNT,
set_flag=SET_FLAG,
)
await accept_ledger_async(delay=1)
response = await submit_and_wait(account_set, client, WALLET)
self.assertTrue(response.result["validated"])
self.assertEqual(response.result["meta"]["TransactionResult"], "tesSUCCESS")
self.assertTrue(response.is_successful())
self.assertEqual(response.result["Fee"], await get_fee(client))
WALLET.sequence += 1

@test_async_and_sync(
globals(),
[
"xrpl.transaction.submit_and_wait",
"xrpl.account.get_next_valid_seq_number",
"xrpl.ledger.get_fee",
],
)
async def test_submit_and_wait_payment(self, client):
payment_transaction = Payment(
account=ACCOUNT,
amount="10",
destination=DESTINATION,
)
await accept_ledger_async(delay=1)
response = await submit_and_wait(payment_transaction, client, WALLET)
self.assertTrue(response.result["validated"])
self.assertEqual(response.result["meta"]["TransactionResult"], "tesSUCCESS")
self.assertTrue(response.is_successful())
self.assertEqual(response.result["Fee"], await get_fee(client))
WALLET.sequence += 1

pdp2121 marked this conversation as resolved.
Show resolved Hide resolved
@test_async_and_sync(
globals(),
[
"xrpl.transaction.autofill_and_sign",
"xrpl.transaction.submit_and_wait",
"xrpl.account.get_next_valid_seq_number",
"xrpl.ledger.get_fee",
],
)
async def test_submit_and_wait_signed(self, client):
payment_transaction = Payment(
account=ACCOUNT,
amount="10",
destination=DESTINATION,
)
payment_transaction_signed = await autofill_and_sign(
payment_transaction, WALLET, client
)
await accept_ledger_async(delay=1)
response = await submit_and_wait(payment_transaction_signed, client)
self.assertTrue(response.result["validated"])
self.assertEqual(response.result["meta"]["TransactionResult"], "tesSUCCESS")
self.assertTrue(response.is_successful())
self.assertEqual(response.result["Fee"], await get_fee(client))
WALLET.sequence += 1

@test_async_and_sync(
globals(),
[
"xrpl.transaction.autofill_and_sign",
"xrpl.transaction.submit_and_wait",
"xrpl.account.get_next_valid_seq_number",
"xrpl.ledger.get_fee",
"xrpl.core.binarycodec.main.encode",
],
)
async def test_submit_and_wait_blob(self, client):
payment_transaction = Payment(
account=ACCOUNT,
amount="10",
destination=DESTINATION,
)
payment_transaction_signed = await autofill_and_sign(
payment_transaction, WALLET, client
)
await accept_ledger_async(delay=1)
payment_transaction_signed_blob = encode(payment_transaction_signed.to_xrpl())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is perhaps a separate ticket, but encode(tx.to_xrpl()) feels like a good helper function on the Transaction object (something like tx.blob()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added the helper function for this ticket.

response = await submit_and_wait(payment_transaction_signed_blob, client)
self.assertTrue(response.result["validated"])
self.assertEqual(response.result["meta"]["TransactionResult"], "tesSUCCESS")
self.assertTrue(response.is_successful())
self.assertEqual(response.result["Fee"], await get_fee(client))
WALLET.sequence += 1

@test_async_and_sync(
globals(),
[
"xrpl.transaction.submit_and_wait",
"xrpl.account.get_next_valid_seq_number",
"xrpl.ledger.get_latest_validated_ledger_sequence",
],
)
async def test_submit_and_wait_last_ledger_expiration(self, client):
payment_transaction = Payment(
account=ACCOUNT,
last_ledger_sequence=await get_latest_validated_ledger_sequence(client),
fee="10",
amount="100",
destination=DESTINATION,
)
await accept_ledger_async(delay=1)
with self.assertRaises(XRPLReliableSubmissionException):
await submit_and_wait(payment_transaction, client, WALLET)
JST5000 marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions xrpl/asyncio/transaction/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from xrpl.asyncio.transaction.reliable_submission import (
XRPLReliableSubmissionException,
send_reliable_submission,
submit_and_wait,
)

__all__ = [
Expand All @@ -27,6 +28,7 @@
"sign",
"sign_and_submit",
"submit",
"submit_and_wait",
"submit_transaction",
"transaction_json_to_binary_codec_form",
"send_reliable_submission",
Expand Down
9 changes: 8 additions & 1 deletion xrpl/asyncio/transaction/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,18 @@ async def autofill_and_sign(
async def submit(
transaction: Transaction,
client: Client,
*,
fail_hard: bool = False,
) -> Response:
"""
Submits a transaction to the ledger.

Args:
transaction: the Transaction to be submitted.
client: the network client with which to submit the transaction.
fail_hard: an optional boolean. If True, and the transaction fails for
the initial server, do not retry or relay the transaction to other
servers. Defaults to False.

Returns:
The response from the ledger.
Expand All @@ -162,7 +167,9 @@ async def submit(
XRPLRequestFailureException: if the rippled API call fails.
"""
transaction_blob = encode(transaction.to_xrpl())
response = await client._request_impl(SubmitOnly(tx_blob=transaction_blob))
response = await client._request_impl(
SubmitOnly(tx_blob=transaction_blob, fail_hard=fail_hard)
)
if response.is_successful():
return response

Expand Down
Loading