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

feature: add auto restore functionality for contract client #991

Merged
merged 21 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8307a74
add auto restore functionality for contract client
BlaineHeffron May 28, 2024
56ccdd8
Update test/unit/server/soroban/assembled_transaction_test.js
BlaineHeffron May 29, 2024
5ba241a
Update test/unit/server/soroban/assembled_transaction_test.js
BlaineHeffron May 29, 2024
133051a
Update src/contract/assembled_transaction.ts
BlaineHeffron May 29, 2024
f5092b2
extract getAccount to utils
BlaineHeffron May 29, 2024
2dcfbaa
TSDoc format
BlaineHeffron May 29, 2024
986ee7c
make account optional for restoreFootprint
BlaineHeffron May 29, 2024
26a2648
remove bald booleans
BlaineHeffron May 29, 2024
ad02f9f
cleanup, remove updateTimeout workaround, dont rebuild sorobandata
BlaineHeffron Jun 5, 2024
2a2ce15
add changelog entry for auto restore functionality
BlaineHeffron Jun 5, 2024
0d096d1
remove comment
BlaineHeffron Jun 5, 2024
08ab269
remove unused var
BlaineHeffron Jun 5, 2024
e5db079
simpler wording
BlaineHeffron Jun 5, 2024
1dccd9b
fixed position of changelog entry
BlaineHeffron Jun 5, 2024
87ca94f
add space after `if` in src/contract/assembled_transaction.ts
chadoh Jun 13, 2024
319d577
add space after `if` in src/contract/assembled_transaction.ts
chadoh Jun 13, 2024
d009c0e
switch order of isSimulationRestore and `restore` check
chadoh Jun 13, 2024
ead51f5
add stub result when simulation returns blank
chadoh Jun 13, 2024
2654c10
add note about restoreTransaction arg
chadoh Jun 13, 2024
c96e8c6
fix missing check from merge with toXDR / fromXDR feature
BlaineHeffron Jun 14, 2024
1c761ef
fix empty scVal construction
BlaineHeffron Jun 14, 2024
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
Prev Previous commit
Next Next commit
cleanup, remove updateTimeout workaround, dont rebuild sorobandata
  • Loading branch information
BlaineHeffron authored and chadoh committed Jun 13, 2024
commit ad02f9fcd034c94ec8c54e743938768e1fa8618c
44 changes: 16 additions & 28 deletions src/contract/assembled_transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ export class AssembledTransaction<T> {
*/
static Errors = {
ExpiredState: class ExpiredStateError extends Error { },
RestoreFailure: class RestoreFailureError extends Error { },
RestorationFailure: class RestoreFailureError extends Error { },
NeedsMoreSignatures: class NeedsMoreSignaturesError extends Error { },
NoSignatureNeeded: class NoSignatureNeededError extends Error { },
NoUnsignedNonInvokerAuthEntries: class NoUnsignedNonInvokerAuthEntriesError extends Error { },
Expand All @@ -330,8 +330,8 @@ export class AssembledTransaction<T> {
method: this.options.method,
tx: this.built?.toXDR(),
simulationResult: {
auth: this.simulationData.result.auth.map((a) => a.toXDR("base64")),
retval: this.simulationData.result.retval.toXDR("base64"),
auth: this.simulationData.result?.auth.map((a) => a.toXDR("base64")),
retval: this.simulationData.result?.retval.toXDR("base64"),
},
simulationTransactionData:
this.simulationData.transactionData.toXDR("base64"),
Expand Down Expand Up @@ -416,8 +416,6 @@ export class AssembledTransaction<T> {
});
}



/**
* Construct a new AssembledTransaction. This is the only way to create a new
* AssembledTransaction; the main constructor is private.
Expand Down Expand Up @@ -518,7 +516,7 @@ export class AssembledTransaction<T> {
await this.simulate();
return this;
}
throw new AssembledTransaction.Errors.RestoreFailure(
throw new AssembledTransaction.Errors.RestorationFailure(
`Automatic restore failed! You set 'restore: true' but the attempted restore did not work. Result:\n${JSON.stringify(result)}`
);
}
Expand All @@ -534,7 +532,7 @@ export class AssembledTransaction<T> {
};

get simulationData(): {
result: Api.SimulateHostFunctionResult;
result?: Api.SimulateHostFunctionResult;
chadoh marked this conversation as resolved.
Show resolved Hide resolved
transactionData: xdr.SorobanTransactionData;
} {
if (this.simulationResult && this.simulationTransactionData) {
Expand All @@ -561,15 +559,15 @@ export class AssembledTransaction<T> {
);
}

if (!simulation.result) {
/*if (!simulation.result) {
throw new Error(
`Expected an invocation simulation, but got no 'result' field. Simulation: ${JSON.stringify(
simulation,
null,
2,
)}`,
);
}
}*/

// add to object for serialization & deserialization
this.simulationResult = simulation.result;
Expand All @@ -583,7 +581,10 @@ export class AssembledTransaction<T> {

get result(): T {
try {
return this.options.parseResultXdr(this.simulationData.result.retval);
if(!this.simulationData.result){
chadoh marked this conversation as resolved.
Show resolved Hide resolved
throw new Error("No simulation result!");
}
return this.options.parseResultXdr(this.simulationData.result?.retval);
chadoh marked this conversation as resolved.
Show resolved Hide resolved
} catch (e) {
if (!implementsToString(e)) throw e;
const err = this.parseError(e.toString());
Expand Down Expand Up @@ -612,7 +613,6 @@ export class AssembledTransaction<T> {
signAndSend = async ({
force = false,
signTransaction = this.options.signTransaction,
updateTimeout = true,
}: {
/**
* If `true`, sign and send the transaction even if it is a read call
Expand All @@ -622,11 +622,6 @@ export class AssembledTransaction<T> {
* You must provide this here if you did not provide one before
*/
signTransaction?: ClientOptions["signTransaction"];
/**
* Whether or not to update the timeout value before signing
* and sending the transaction
*/
updateTimeout?: boolean;
} = {}): Promise<SentTransaction<T>> => {
if (!this.built) {
throw new Error("Transaction has not yet been simulated");
Expand Down Expand Up @@ -657,7 +652,6 @@ export class AssembledTransaction<T> {
const sent = await SentTransaction.init(
signTransaction,
typeChecked,
updateTimeout
);
return sent;
};
Expand Down Expand Up @@ -843,7 +837,7 @@ export class AssembledTransaction<T> {
* returns `false`, then you need to call `signAndSend` on this transaction.
*/
get isReadCall(): boolean {
const authsCount = this.simulationData.result.auth.length;
const authsCount = this.simulationData.result?.auth.length;
chadoh marked this conversation as resolved.
Show resolved Hide resolved
const writeLength = this.simulationData.transactionData
.resources()
.footprint()
Expand Down Expand Up @@ -880,9 +874,7 @@ export class AssembledTransaction<T> {
minResourceFee: string;
transactionData: SorobanDataBuilder;
},
/**
* The account that is executing the footprint restore operation.
*/
/** The account that is executing the footprint restore operation. */
chadoh marked this conversation as resolved.
Show resolved Hide resolved
account?: Account
): Promise<Api.GetTransactionResponse> {
if(!this.options.signTransaction){
chadoh marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -896,14 +888,10 @@ export class AssembledTransaction<T> {
account,
restorePreamble.minResourceFee
);
const sentTransaction = await restoreTx.signAndSend({
updateTimeout: false,
force: true,
});
const sentTransaction = await restoreTx.signAndSend();
if (!sentTransaction.getTransactionResponse) {
// todo make better error message
throw new AssembledTransaction.Errors.RestoreFailure(
`Failure during restore. \n${JSON.stringify(sentTransaction)}`
throw new AssembledTransaction.Errors.RestorationFailure(
`The attempt at automatic restore failed. \n${JSON.stringify(sentTransaction)}`
);
}
return sentTransaction.getTransactionResponse;
Expand Down
25 changes: 10 additions & 15 deletions src/contract/sent_transaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* disable max-classes rule, because extending error shouldn't count! */
/* eslint max-classes-per-file: 0 */
import { SorobanDataBuilder, TransactionBuilder } from "@stellar/stellar-base";
import { TransactionBuilder } from "@stellar/stellar-base";
import type { ClientOptions, MethodOptions, Tx } from "./types";
import { Server } from "../rpc/server"
import { Api } from "../rpc/api"
Expand Down Expand Up @@ -76,27 +76,22 @@ export class SentTransaction<T> {
signTransaction: ClientOptions["signTransaction"],
/** {@link AssembledTransaction} from which this SentTransaction was initialized */
assembled: AssembledTransaction<U>,
updateTimeout: boolean = true,
): Promise<SentTransaction<U>> => {
const tx = new SentTransaction(signTransaction, assembled);
const sent = await tx.send({ updateTimeout });
const sent = await tx.send();
return sent;
};

private send = async ({ updateTimeout }: {updateTimeout?: boolean } = { updateTimeout: true }): Promise<this> => {
private send = async (): Promise<this> => {
const timeoutInSeconds =
this.assembled.options.timeoutInSeconds ?? DEFAULT_TIMEOUT;
if(updateTimeout) {
this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, {
fee: this.assembled.built!.fee,
timebounds: undefined,
sorobanData: new SorobanDataBuilder(
this.assembled.simulationData.transactionData.toXDR(),
).build(),
})
.setTimeout(timeoutInSeconds)
.build();
}
this.assembled.built = TransactionBuilder.cloneFrom(this.assembled.built!, {
fee: this.assembled.built!.fee,
timebounds: undefined, // intentionally don't clone timebounds
sorobanData: this.assembled.simulationData.transactionData
})
.setTimeout(timeoutInSeconds)
.build();

const signature = await this.signTransaction!(
// `signAndSend` checks for `this.built` before calling `SentTransaction.init`
Expand Down
4 changes: 1 addition & 3 deletions test/unit/server/soroban/assembled_transaction_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ describe("AssembledTransaction.buildFootprintRestoreTransaction", () => {
),
52641,
)
.then((txn) => txn.signAndSend({force: true, ...wallet,
updateTimeout: false
}))
.then((txn) => txn.signAndSend({ ...wallet }))
.then((result) => {
expect(result.getTransactionResponse.status).to.equal(rpc.Api.GetTransactionStatus.SUCCESS);
done();
Expand Down