Skip to content

Commit

Permalink
Fix tx submission error handling across the app (PUT errors were not …
Browse files Browse the repository at this point in the history
…reported correctly) (#30)
  • Loading branch information
paluh authored Dec 13, 2023
1 parent 6dea548 commit e821ac3
Show file tree
Hide file tree
Showing 22 changed files with 504 additions and 84 deletions.
1 change: 1 addition & 0 deletions e2e/artifacts/wallets/no-pure-ada-utxo/mnemonic
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flame build shy opera chef educate crane high acquire season negative syrup senior lecture false float dwarf quit fancy couple lizard grief buffalo bundle
1 change: 1 addition & 0 deletions e2e/artifacts/wallets/no-pure-ada-utxo/testnet.bech32
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addr_test1qp7thfxtpw5yj2jmej823cgnh5937cv38e7a32k3ece8aerv6hy3dvev273nppcz3qu8dwk92p5atmkyzm9p8lvmv5rqnc06ms
163 changes: 157 additions & 6 deletions e2e/src/features/apply-inputs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,24 @@ Feature: As a user, I would like to apply an input on a current contract
Given I use alice lace browser
Then I should see "Complete" status of the "escrow" contract

@submission-failure-with-empty-wallet
@contract-creation-failure-with-empty-wallet
Scenario Outline: Creating a deposit with a wallet
Given I use alice <wallet_name> browser
Given I use empty lace browser
And I am on the "home" page
When I authorize the app

When I click the "button" with "Create a contract" text
And I generate Escrow contract with "empty" as a buyer and "empty" as a seller and "empty" as a mediator and call it "escrow"

And I enter the json of the contract "escrow" into the "contract-input" field
When I click the "button" with "Submit contract" text And sign the transaction
Then I should see error toast
# The actual error:
# An error occured during contract submission: (ServerApiError ApiError { message: "CoinSelectionFailed \"Insufficient lovelace available for coin selection: valueFromList [(AdaAssetId,8766894)] required, but valueFromList [] available.\"", error: CoinSelectionFailed, details: {"contents":"Insufficient lovelace available for coin selection: valueFromList [(AdaAssetId,8766894)] required, but valueFromList [] available.","tag":"CoinSelectionFailed"} })#

@input-application-failure-with-empty-wallet
Scenario Outline: Creating a deposit with a wallet
Given I use alice lace browser
And I am on the "home" page
When I authorize the app

Expand All @@ -206,15 +221,151 @@ Feature: As a user, I would like to apply an input on a current contract
Then I should see "Syncing" status of the "escrow" contract
Then I should see "Awaiting other party" status of the "escrow" contract

Given I use empty <wallet_name> browser
Given I use empty lace browser
And I am on the "home" page
When I authorize the app
Then I should see "Advance" status of the "escrow" contract

When I start advancing "escrow" contract
And I click the "button" with "Advance contract" text
Then I should see error toast
# The actual error:
# An error occured during contract submission: (ServerApiError ApiError { error: CoinSelectionFailed, message: "CoinSelectionFailed \"No collateral found in [(TxIn \\\"0c338171c1d7a1a7228b60e8ed8a3d168b2fd74853e0cd4bb6fe85aec69786bd\\\" (TxIx 1),TxOut (AddressInEra (ShelleyAddressInEra ShelleyBasedEraBabbage) (ShelleyAddress Testnet (ScriptHashObj (ScriptHash \\\"d85fa9bc2bdfd97d5ebdbc5e3fc66f7476213c40c21b73b41257f09d\\\")) StakeRefNull)) (TxOutValue MultiAssetInBabbageEra (valueFromList [(AdaAssetId,2000000)])) (TxOutDatumInline ReferenceTxInsScriptsInlineDatumsInBabbageEra (HashableScriptData \\\"\\\\216y\\\\159\\\\216y\\\\159@\\\\255\\\\216y (...)"" })

Examples:
| wallet_name |
| lace |
@contract-creation-failure-with-no-pure-ada-utxo
Scenario Outline: Creating a deposit with a wallet
Given I use no-pure-ada-utxo lace browser
And I am on the "home" page
When I authorize the app

When I click the "button" with "Create a contract" text
And I generate Escrow contract with "empty" as a buyer and "empty" as a seller and "empty" as a mediator and call it "escrow"

And I enter the json of the contract "escrow" into the "contract-input" field
When I click the "button" with "Submit contract" text And sign the transaction
Then I should see error toast
# The actual error:
# An error occured during contract submission: (ServerApiError ApiError { message: "CoinSelectionFailed \"Insufficient lovelace available for coin selection: valueFromList [(AdaAssetId,9340124)] required, but valueFromList [(AdaAssetId,5172320),(AssetId \\\"0122e5079749e36fc703335621430e65017231726166e319a32ed831\\\" \\\"Other provider\\\",4),(AssetId \\\"32dada46a8f74bc884627f1258f52777b9a95bd6d0a492ccaabd6d99\\\" \\\"Mediator\\\",4),(AssetId \\\"58a4d8a00bf87cdc21af08c0fbbe0c8d239ea428386df0b1494cfd97\\\" \\\"Withdrawer\\\",4)] available.\"", error: CoinSelectionFailed, details: {"contents":"Insufficient lovelace available for coin selection: valueFromList [(AdaAssetId,9340124)] required, but valueFromList [(AdaAssetId,5172320),(AssetId \"0122e5079749e36fc703335621430e65017231726166e319a32ed831\" \"Other provider\",4),(AssetId \"32dada46a8f74bc884627f1258f52777b9a95bd6d0a492ccaabd6d99\" \"Mediator\",4),(AssetId \"58a4d8a00bf87cdc21af08c0fbbe0c8d239ea428386df0b1494cfd97\" \"Withdrawer\",4)] available.","tag":"CoinSelectionFailed"} })#

@submission-failure-of-input-application-for-closed-contract
Scenario Outline: User tries to apply the input on a closed contract
Given I use alice lace browser
Given I am on the "home" page
When I authorize the app

When I click the "button" with "Create a contract" text
And I generate "DoubleDeposit" contract with "alice" as a first depositor and "bob" as a second depositor and call it "double-deposit"
And I enter the json of the contract "double-deposit" into the "contract-input" field

When I click the "button" with "Submit contract" text And sign the transaction
Then I can see "double-deposit" contract id in the first row in the table

Then I should see success toast and close it
Then I should see "Advance" status of the "double-deposit" contract
# We leave this user on the input application page
When I start advancing "double-deposit" contract

# and switch to the second user
Given I use bob lace browser
Given I am on the "home" page
When I authorize the app
Then I should see "Advance" status of the "double-deposit" contract
When I start advancing "double-deposit" contract
And I click the "checkbox" with "Deposit 2 ₳" text
When I click the "button" with "Advance contract" text And sign the transaction
Then I should see "Syncing" status of the "double-deposit" contract
Then I should see "Complete" status of the "double-deposit" contract

# Now we switch back to the first user
Given I use alice lace browser
When I click the "button" with "Advance contract" text
# FAIULRE
Then I should see error toast
# The actual error:
# An error occured during contract submission: (ServerApiError ApiError { message: "LoadMarloweContextErrorNotFound", error: LoadMarloweContextErrorNotFound, details: {"tag":"LoadMarloweContextErrorNotFound"} })#

@submission-failure-of-exclusive-input-application
Scenario Outline: Two users try to apply the inputs which are exclusive
Given I use alice lace browser
Given I am on the "home" page
When I authorize the app

When I click the "button" with "Create a contract" text
And I generate "DoubleDepositAndNotify" contract with "alice" as a first depositor and "bob" as a second depositor and call it "double-deposit"
And I enter the json of the contract "double-deposit" into the "contract-input" field

When I click the "button" with "Submit contract" text And sign the transaction
Then I can see "double-deposit" contract id in the first row in the table
Then I should see success toast and close it

Then I should see "Advance" status of the "double-deposit" contract
# We leave this user on the input application page
When I start advancing "double-deposit" contract

# and switch to the second user
Given I use bob lace browser
Given I am on the "home" page
When I authorize the app
Then I should see "Advance" status of the "double-deposit" contract
When I start advancing "double-deposit" contract
And I click the "checkbox" with "Deposit 2 ₳" text
When I click the "button" with "Advance contract" text And sign the transaction
Then I should see success toast and close it
Then I should see "Syncing" status of the "double-deposit" contract
Then I should see "Advance" status of the "double-deposit" contract

# Now we switch back to the first user
Given I use alice lace browser
When I click the "button" with "Advance contract" text
# FAIULRE
Then I should see error toast
# The actual error:
# An error occured during contract submission: (ServerApiError ApiError { message: "MarloweComputeTransactionFailed \"TEApplyNoMatchError\"", error: MarloweComputeTransactionFailed, details: {"contents":"TEApplyNoMatchError","tag":"MarloweComputeTransactionFailed"} })#

# This artificial scenario is actually trying to test a behavior and error reporting
# of submission of an invalid transaction.
# * We ask the Runtime to create a transaction and keep it
# * We submit a colliding transaction
# * We try to submit the kept transaction
@input-application-failure-of-expired-transaction
Scenario Outline: Two users try to apply the inputs which are exclusive. The second submission is done using old transaction
Given I use alice lace browser
Given I am on the "home" page
When I authorize the app

When I click the "button" with "Create a contract" text
And I generate "DoubleDepositAndNotify" contract with "alice" as a first depositor and "bob" as a second depositor and call it "double-deposit"
And I enter the json of the contract "double-deposit" into the "contract-input" field

When I click the "button" with "Submit contract" text And sign the transaction
Then I can see "double-deposit" contract id in the first row in the table
Then I should see success toast and close it

Then I should see "Advance" status of the "double-deposit" contract
# We leave this user on the input application page
When I start advancing "double-deposit" contract
When I click the "button" with "Advance contract" text And grab wallet popup

# and switch to the second user
Given I use bob lace browser
Given I am on the "home" page
When I authorize the app
Then I should see "Advance" status of the "double-deposit" contract
When I start advancing "double-deposit" contract
And I click the "checkbox" with "Deposit 2 ₳" text
When I click the "button" with "Advance contract" text And sign the transaction
Then I should see success toast and close it
Then I should see "Syncing" status of the "double-deposit" contract
Then I should see "Advance" status of the "double-deposit" contract

# Now we switch back to the first user
Given I switch to "alice" lace browser and finally sign the transaction
Then I should see error toast
# The actual error:
# Status Code: 403
# {
# "details": null,
# "errorCode": "SubmissionError",
# "message": "SubmitFailed \"TxValidationErrorInMode (ShelleyTxValidationError ShelleyBasedEraBabbage (ApplyTxError [UtxowFailure (AlonzoInBabbageUtxowPredFailure (NonOutputSupplimentaryDatums (fromList [SafeHash \\\"68534c553c71d5435372939ddcb3befe73f51d4036c6651d8ad122be55b45085\\\"]) (fromList [SafeHash \\\"14a0df629b39faa3b76b8c2aaaa59d7cbfe9e5f297a1f785b7e9660c37f1c53f\\\"]))),UtxowFailure (AlonzoInBabbageUtxowPredFailure (ExtraRedeemers [RdmrPtr Spend 1])),UtxowFailure (AlonzoInBabbageUtxowPredFailure (PPViewHashesDontMatch (SJust (SafeHash \\\"1557169995ed8cb99308b23de184cc46e8ea43a41024df2bba978ac76906584f\\\")) (SJust (SafeHash \\\"27641f03212d3ab79d4c420a630e6db8586edb40fb1d8eadfbb42b3303ef6e79\\\")))),UtxowFailure (UtxoFailure (AlonzoInBabbageUtxoPredFailure (ValueNotConservedUTxO (MaryValue 7790191 (MultiAsset (fromList []))) (MaryValue 9790191 (MultiAsset (fromList [])))))),UtxowFailure (UtxoFailure (AlonzoInBabbageUtxoPredFailure (BadInputsUTxO (fromList [TxIn (TxId {unTxId = SafeHash \\\"eea2f67cce5ccb720897f10365d9c8bee81c4c8af3192cdc27bdf598dc173b5f\\\"}) (TxIx 1)]))))])) BabbageEraInCardanoMode\""
# }
#
11 changes: 10 additions & 1 deletion e2e/src/step-definitions/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@ When(
/^I should see (error|success) toast$/,
async function(this: ScenarioWorld, toastType: ToastType) {
const { page } = this.getScreen();
await waitForTestIdVisible(page, "toast-" + toastType + "-msg");
await waitForTestIdVisible(page, "toast-" + toastType + "-msg", 600000);
}
)

When(
/^I should see (error|success) toast and close it$/,
async function(this: ScenarioWorld, toastType: ToastType) {
const { page } = this.getScreen();
const toast = await waitForTestIdVisible(page, "toast-" + toastType + "-msg", 60000);
const closeButton = toast.locator(".btn-close");
await closeButton.click();
}
)
26 changes: 25 additions & 1 deletion e2e/src/step-definitions/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,28 @@ When(
}
);


// And I generate "SimpleNotify" and call it "notify"
When(
/^I generate "([^"]*)" and call it "([^"]*)"$/,
async function(this: ScenarioWorld, contractName: string, contractNickname: string) {
const walletAddress = await this.getWalletAddress();
let contract: Contract;
switch (contractName) {
case "SimpleDeposit":
contract = mkSimpleDeposit(walletAddress);
break;
case "SimpleChoice":
contract = mkSimpleChoice(walletAddress);
break;
case "TimedOutSimpleChoice":
contract = mkTimedOutSimpleChoice(walletAddress);
break;
case "SimpleNotify":
contract = mkSimpleNotify();
break;
default:
throw new Error("Unknown contract type: " + contractName);
}
this.setContractInfo(contractNickname, { contract: contract, contractId: undefined });
}
);
46 changes: 46 additions & 0 deletions e2e/src/step-definitions/contracts/doubleDeposit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { When } from '@cucumber/cucumber';
import { ScenarioWorld } from '../world.js';
import {
Contract,
datetoTimeout,
} from "@marlowe.io/language-core-v1";
import { Bech32 } from '../../cardano.js';


const mkDoubleDeposit = (address1: Bech32, address2: Bech32): Contract => {
const twentyMinutesInMilliseconds = 20 * 60 * 1000;
const inTwentyMinutes = datetoTimeout(new Date(Date.now() + twentyMinutesInMilliseconds));
return {
timeout: inTwentyMinutes,
timeout_continuation: "close",
when: [
{ case: {
party: {address: address1.toString()},
deposits: 1000000n,
of_token: { currency_symbol: "", token_name: "" },
into_account: {address: address1.toString()}
},
then: "close",
},
{ case: {
party: {address: address2.toString()},
deposits: 2000000n,
of_token: { currency_symbol: "", token_name: "" },
into_account: {address: address2.toString()}
},
then: "close",
},
]
};
}

When(
/^I generate "DoubleDeposit" contract with "([^"]*)" as a first depositor and "([^"]*)" as a second depositor and call it "([^"]*)"$/,
async function(this: ScenarioWorld, first: string, second: string, contractNickname: string) {
const firstAddress = await this.getWalletAddress(first);
const secondAddress = await this.getWalletAddress(second);
const contract = mkDoubleDeposit(firstAddress, secondAddress);
this.setContractInfo(contractNickname, { contract: contract, contractId: undefined });
}
);

59 changes: 59 additions & 0 deletions e2e/src/step-definitions/contracts/doubleDepositAndNotify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { When } from '@cucumber/cucumber';
import { ScenarioWorld } from '../world.js';
import {
Contract,
datetoTimeout,
} from "@marlowe.io/language-core-v1";
import { Bech32 } from '../../cardano.js';


const mkDoubleDepositAndNotify = (address1: Bech32, address2: Bech32): Contract => {
const twentyMinutesInMilliseconds = 20 * 60 * 1000;
const inTwentyMinutes = datetoTimeout(new Date(Date.now() + twentyMinutesInMilliseconds));
const notifyContinuation:Contract = {
timeout: inTwentyMinutes,
timeout_continuation: "close",
"when": [
{
"then": "close",
"case": {
"notify_if": true
}
}
],
};

return {
timeout: inTwentyMinutes,
timeout_continuation: "close",
when: [
{ case: {
party: {address: address1.toString()},
deposits: 1000000n,
of_token: { currency_symbol: "", token_name: "" },
into_account: {address: address1.toString()}
},
then: notifyContinuation,
},
{ case: {
party: {address: address2.toString()},
deposits: 2000000n,
of_token: { currency_symbol: "", token_name: "" },
into_account: {address: address2.toString()}
},
then: notifyContinuation,
},
]
};
}

When(
/^I generate "DoubleDepositAndNotify" contract with "([^"]*)" as a first depositor and "([^"]*)" as a second depositor and call it "([^"]*)"$/,
async function(this: ScenarioWorld, first: string, second: string, contractNickname: string) {
const firstAddress = await this.getWalletAddress(first);
const secondAddress = await this.getWalletAddress(second);
const contract = mkDoubleDepositAndNotify(firstAddress, secondAddress);
this.setContractInfo(contractNickname, { contract: contract, contractId: undefined });
}
);

1 change: 1 addition & 0 deletions e2e/src/step-definitions/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ After(async function(this: ScenarioWorld, scenario) {

if (scenarioStatus === 'FAILED' && screen) {
const page = screen.page;
await page.evaluate(() => window.scrollTo(0, 0))
const screenshot = await page.screenshot({
path: `${env('SCREENSHOT_PATH')}${scenario.pickle.name}.png`
});
Expand Down
7 changes: 7 additions & 0 deletions e2e/src/step-definitions/popup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Page } from "playwright";

export const grabPopup = async function (page: Page, triggerPopup: () => Promise<void>): Promise<Page> {
const popupPromise:Promise<Page> = new Promise(resolve => page.context().once('page', resolve));
await triggerPopup();
return await popupPromise;
}
Loading

0 comments on commit e821ac3

Please sign in to comment.