-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add print functionality to Soroban contracts (#1659)
This PR adds static string print functionality to Soroban contracts. This serves the following: 1. `print()` statements 2. Logging runtime errors. However, the following findings might be interesting: In both Solana and Polkadot, the VM execution capacity can grasp a call to `vector_new` in the `stdlib`: https://github.com/hyperledger/solang/blob/06798cdeac6fd62ee98f5ae7da38f3af4933dc0f/stdlib/stdlib.c#L167 However, Soroban doesn't. That's why Soroban would need Solang to implement a more efficient way of printing dynamic strings. @leighmcculloch Signed-off-by: salaheldinsoliman <[email protected]>
- Loading branch information
1 parent
df692d5
commit 420fbb8
Showing
14 changed files
with
326 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,5 @@ | |
!package.json | ||
node_modules | ||
package-lock.json | ||
*.txt | ||
*.toml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
contract Error { | ||
uint64 count = 1; | ||
|
||
/// @notice Calling this function twice will cause an overflow | ||
function decrement() public returns (uint64){ | ||
count -= 1; | ||
return count; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,64 @@ | ||
import * as StellarSdk from '@stellar/stellar-sdk'; | ||
|
||
|
||
|
||
export async function call_contract_function(method, server, keypair, contract) { | ||
let res = null; | ||
|
||
let res; | ||
let builtTransaction = new StellarSdk.TransactionBuilder(await server.getAccount(keypair.publicKey()), { | ||
fee: StellarSdk.BASE_FEE, | ||
networkPassphrase: StellarSdk.Networks.TESTNET, | ||
}).addOperation(contract.call(method)).setTimeout(30).build(); | ||
|
||
let preparedTransaction = await server.prepareTransaction(builtTransaction); | ||
|
||
// Sign the transaction with the source account's keypair. | ||
preparedTransaction.sign(keypair); | ||
|
||
try { | ||
let sendResponse = await server.sendTransaction(preparedTransaction); | ||
if (sendResponse.status === "PENDING") { | ||
let getResponse = await server.getTransaction(sendResponse.hash); | ||
// Poll `getTransaction` until the status is not "NOT_FOUND" | ||
while (getResponse.status === "NOT_FOUND") { | ||
console.log("Waiting for transaction confirmation..."); | ||
// See if the transaction is complete | ||
getResponse = await server.getTransaction(sendResponse.hash); | ||
// Wait one second | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); | ||
} | ||
|
||
if (getResponse.status === "SUCCESS") { | ||
// Make sure the transaction's resultMetaXDR is not empty | ||
if (!getResponse.resultMetaXdr) { | ||
throw "Empty resultMetaXDR in getTransaction response"; | ||
} | ||
// Find the return value from the contract and return it | ||
let transactionMeta = getResponse.resultMetaXdr; | ||
let returnValue = transactionMeta.v3().sorobanMeta().returnValue(); | ||
console.log(`Transaction result: ${returnValue.value()}`); | ||
res = returnValue.value(); | ||
let builtTransaction = new StellarSdk.TransactionBuilder(await server.getAccount(keypair.publicKey()), { | ||
fee: StellarSdk.BASE_FEE, | ||
networkPassphrase: StellarSdk.Networks.TESTNET, | ||
}).addOperation(contract.call(method)).setTimeout(30).build(); | ||
|
||
let preparedTransaction = await server.prepareTransaction(builtTransaction); | ||
|
||
// Sign the transaction with the source account's keypair. | ||
preparedTransaction.sign(keypair); | ||
|
||
let sendResponse = await server.sendTransaction(preparedTransaction); | ||
|
||
if (sendResponse.status === "PENDING") { | ||
let getResponse = await server.getTransaction(sendResponse.hash); | ||
// Poll `getTransaction` until the status is not "NOT_FOUND" | ||
while (getResponse.status === "NOT_FOUND") { | ||
console.log("Waiting for transaction confirmation..."); | ||
// Wait one second | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); | ||
// See if the transaction is complete | ||
getResponse = await server.getTransaction(sendResponse.hash); | ||
} | ||
|
||
if (getResponse.status === "SUCCESS") { | ||
// Ensure the transaction's resultMetaXDR is not empty | ||
if (!getResponse.resultMetaXdr) { | ||
throw "Empty resultMetaXDR in getTransaction response"; | ||
} | ||
// Extract and return the return value from the contract | ||
let transactionMeta = getResponse.resultMetaXdr; | ||
let returnValue = transactionMeta.v3().sorobanMeta().returnValue(); | ||
console.log(`Transaction result: ${returnValue.value()}`); | ||
res = returnValue.value(); | ||
} else { | ||
throw `Transaction failed: ${getResponse.resultXdr}`; | ||
} | ||
} else if (sendResponse.status === "FAILED") { | ||
// Handle expected failure and return the error message | ||
if (sendResponse.errorResultXdr) { | ||
const errorXdr = StellarSdk.xdr.TransactionResult.fromXDR(sendResponse.errorResultXdr, 'base64'); | ||
const errorRes = errorXdr.result().results()[0].tr().invokeHostFunctionResult().code().value; | ||
console.log(`Transaction error: ${errorRes}`); | ||
res = errorRes; | ||
} else { | ||
throw "Transaction failed but no errorResultXdr found"; | ||
} | ||
} else { | ||
throw `Transaction failed: ${getResponse.resultXdr}`; | ||
throw sendResponse.errorResultXdr; | ||
} | ||
} else { | ||
throw sendResponse.errorResultXdr; | ||
} | ||
} catch (err) { | ||
// Catch and report any errors we've thrown | ||
console.log("Sending transaction failed"); | ||
console.log(err); | ||
// Return the error as a string instead of failing the test | ||
console.log("Transaction processing failed"); | ||
console.log(err); | ||
res = err.toString(); | ||
} | ||
|
||
return res; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.