Skip to content

Commit

Permalink
Properly parse simulateTransaction response variations (#146)
Browse files Browse the repository at this point in the history
* The docs say it's a string, not an integer:
https://soroban.stellar.org/api/methods/getEvents
* Update numbers to strings in various ledger fields
* Update schema detection code to work w/ RPC
  • Loading branch information
Shaptic committed Sep 14, 2023
1 parent 828440f commit d4295f7
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 30 deletions.
20 changes: 12 additions & 8 deletions src/soroban_rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export namespace SorobanRpc {

interface GetAnyTransactionResponse {
status: GetTransactionStatus;
latestLedger: number;
latestLedger: string;
latestLedgerCloseTime: number;
oldestLedger: number;
oldestLedger: string;
oldestLedgerCloseTime: number;
}

Expand Down Expand Up @@ -98,9 +98,9 @@ export namespace SorobanRpc {

export interface RawGetTransactionResponse {
status: GetTransactionStatus;
latestLedger: number;
latestLedger: string;
latestLedgerCloseTime: number;
oldestLedger: number;
oldestLedger: string;
oldestLedgerCloseTime: number;

// the fields below are set if status is SUCCESS
Expand All @@ -122,7 +122,7 @@ export namespace SorobanRpc {
}

export interface GetEventsResponse {
latestLedger: number;
latestLedger: string;
events: EventResponse[];
}

Expand Down Expand Up @@ -186,7 +186,7 @@ export namespace SorobanRpc {
id: string;

/** always present: the LCL known to the server when responding */
latestLedger: number;
latestLedger: string;

/**
* The field is always present, but may be empty in cases where:
Expand All @@ -195,6 +195,9 @@ export namespace SorobanRpc {
* @see {@link humanizeEvents}
*/
events: xdr.DiagnosticEvent[];

/** a private field to mark the schema as parsed */
_parsed: boolean;
}

/** Includes simplified fields only present on success. */
Expand Down Expand Up @@ -245,7 +248,8 @@ export namespace SorobanRpc {

export function isSimulationRestore(sim: SimulateTransactionResponse):
sim is SimulateTransactionRestoreResponse {
return isSimulationSuccess(sim) && 'restorePreamble' in sim;
return isSimulationSuccess(sim) && 'restorePreamble' in sim &&
!!sim.restorePreamble.transactionData;
}

interface RawSimulateHostFunctionResult {
Expand All @@ -258,7 +262,7 @@ export namespace SorobanRpc {
/** @see https://soroban.stellar.org/api/methods/simulateTransaction#returns */
export interface RawSimulateTransactionResponse {
id: string;
latestLedger: number;
latestLedger: string;
error?: string;
// this is an xdr.SorobanTransactionData in base64
transactionData?: string;
Expand Down
24 changes: 4 additions & 20 deletions src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export function parseRawSimulation(

// shared across all responses
let base: SorobanRpc.BaseSimulateTransactionResponse = {
_parsed: true,
id: sim.id,
latestLedger: sim.latestLedger,
events: sim.events?.map(
Expand Down Expand Up @@ -171,7 +172,7 @@ function parseSuccessful(
)
};

if (!sim.restorePreamble) {
if (!sim.restorePreamble || sim.restorePreamble.transactionData === '') {
return success;
}

Expand All @@ -187,29 +188,12 @@ function parseSuccessful(
};
}


function isSimulationRaw(
export function isSimulationRaw(
sim:
| SorobanRpc.SimulateTransactionResponse
| SorobanRpc.RawSimulateTransactionResponse
): sim is SorobanRpc.RawSimulateTransactionResponse {
const asGud = sim as SorobanRpc.SimulateTransactionRestoreResponse;
const asRaw = sim as SorobanRpc.RawSimulateTransactionResponse;

// lazy checks to determine type: check existence of parsed-only fields note
return (
asRaw.restorePreamble !== undefined ||
!(
asGud.restorePreamble !== undefined ||
asGud.result !== undefined ||
typeof asGud.transactionData !== 'string'
) ||
(asRaw.error !== undefined && (
!asRaw.events?.length ||
typeof asRaw.events![0] === 'string'
)) ||
(asRaw.results ?? []).length > 0
);
return !(sim as SorobanRpc.SimulateTransactionResponse)._parsed;
}

function isSorobanTransaction(tx: Transaction): boolean {
Expand Down
47 changes: 45 additions & 2 deletions test/unit/server/simulate_transaction_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ describe('Server#simulateTransaction', function () {
),
retval: xdr.ScVal.fromXDR(simulationResponse.results[0].xdr, 'base64')
},
cost: simulationResponse.cost
cost: simulationResponse.cost,
_parsed: true
};

beforeEach(function () {
Expand Down Expand Up @@ -167,7 +168,8 @@ function cloneSimulation(sim) {
),
retval: xdr.ScVal.fromXDR(sim.result.retval.toXDR())
},
cost: sim.cost
cost: sim.cost,
_parsed: sim._parsed
};
}

Expand Down Expand Up @@ -235,3 +237,44 @@ function invokeSimulationResponseWithRestoration(address) {
}
};
}

describe('works with real responses', function () {
const schema = {
transactionData:
'AAAAAAAAAAIAAAAGAAAAAa/6eoLeofDK5ksPljSZ7t/rAj/XR18e40fCB9LBugstAAAAFAAAAAEAAAAHqA0LEZLq3WL+N3rBQLTWuPqdV3Vv6XIAGeBJaz1wMdsAAAAAABg1gAAAAxwAAAAAAAAAAAAAAAk=',
minResourceFee: '27889',
events: [
'AAAAAQAAAAAAAAAAAAAAAgAAAAAAAAADAAAADwAAAAdmbl9jYWxsAAAAAA0AAAAgr/p6gt6h8MrmSw+WNJnu3+sCP9dHXx7jR8IH0sG6Cy0AAAAPAAAABWhlbGxvAAAAAAAADwAAAAVBbG9oYQAAAA==',
'AAAAAQAAAAAAAAABr/p6gt6h8MrmSw+WNJnu3+sCP9dHXx7jR8IH0sG6Cy0AAAACAAAAAAAAAAIAAAAPAAAACWZuX3JldHVybgAAAAAAAA8AAAAFaGVsbG8AAAAAAAAQAAAAAQAAAAIAAAAPAAAABUhlbGxvAAAAAAAADwAAAAVBbG9oYQAAAA=='
],
results: [
{
auth: [],
xdr: 'AAAAEAAAAAEAAAACAAAADwAAAAVIZWxsbwAAAAAAAA8AAAAFQWxvaGEAAAA='
}
],
cost: {
cpuInsns: '1322134',
memBytes: '1207047'
},
restorePreamble: {
transactionData: '',
minResourceFee: '0'
},
latestLedger: '2634'
};

it('parses the schema', function () {
expect(SorobanClient.isSimulationRaw(schema)).to.be.true;

const parsed = SorobanClient.parseRawSimulation(schema);

expect(parsed.results).to.be.undefined;
expect(parsed.result.auth).to.be.empty;
expect(parsed.result.retval).to.be.instanceOf(xdr.ScVal);
expect(parsed.transactionData).to.be.instanceOf(SorobanDataBuilder);
expect(parsed.events).to.be.lengthOf(2);
expect(parsed.events[0]).to.be.instanceOf(xdr.DiagnosticEvent);
expect(parsed.restorePreamble).to.be.undefined;
});
});

0 comments on commit d4295f7

Please sign in to comment.