
{"id":214415,"date":"2026-08-17T16:42:56","date_gmt":"2026-08-17T16:42:56","guid":{"rendered":"https:\/\/mycryptomania.com\/?p=214415"},"modified":"2026-08-17T16:42:56","modified_gmt":"2026-08-17T16:42:56","slug":"roflize-an-app-bonus-guide-to-features-troubleshooting-part-2","status":"publish","type":"post","link":"https:\/\/mycryptomania.com\/?p=214415","title":{"rendered":"ROFLize an App: Bonus Guide to Features &amp; Troubleshooting (Part 2)"},"content":{"rendered":"<p>In this 2-part bonus guide on the features and troubleshooting once you ROFLize an app, the <a href=\"https:\/\/medium.com\/coinmonks\/roflize-an-app-bonus-guide-to-features-troubleshooting-part-1-4db74b3e94d2\">first part<\/a> covered in detail the marketplace, secrets, and persistent storage. Let\u2019s continue.<\/p>\n<h3>Public Variables<\/h3>\n<p>You will remember that we learned about secrets for confidential values. But an app may also consist of containers that need to access non-sensitive values and configurations. API endpoints, contract addresses, feature flags, etc are some examples of information that do not have or need any confidential attributes. This is when we use <strong>public variables<\/strong>. They are basically arbitrary key-value pairs that are exposed to containers as environment variables.<\/p>\n<p>You can manage these public variables using the <a href=\"https:\/\/docs.oasis.io\/build\/tools\/cli\/rofl#public-var\">Oasis CLI<\/a>. Take this example where we create a public variable called\u00a0API_URL.<\/p>\n<p>echo -n &#8220;https:\/\/api.example.com&#8221; | oasis rofl public-var set API_URL &#8211;<\/p>\n<p>You will notice that this command only updates the local app manifest file. The public variable, however, is not yet propagated to the app. As a result, you will be able to easily configure as many public variables as you want without having to constantly update the on-chain app configuration.<\/p>\n<p>Once the required public variables are created, you can update all of them in the on-chain configuration using the usual\u00a0command.<\/p>\n<p>oasis rofl update<\/p>\n<p>The Oasis CLI documentation is useful if you need to consult comprehensive public variable management commands, including importing from\u00a0.env files, removing public variables, and other advanced features.<\/p>\n<p>Now, inside the containers, the public variables can be passed via environment variables. This is possible because each public variable is automatically exposed in the Compose environment and can be used in the Compose\u00a0file.<\/p>\n<p>services:<br \/>  test:<br \/>    image: docker.io\/library\/alpine:3.21.2@sha256:f3240395711384fc3c07daa46cbc8d73aa5ba25ad1deb97424992760f8cb2b94<br \/>    command: echo &#8220;API URL is $API_URL&#8221;<br \/>    environment:<br \/>      &#8211; API_URL=${API_URL}<\/p>\n<h3>rofl.yaml Manifest\u00a0File<\/h3>\n<p>Before proceeding in this section, let\u2019s familiarize ourselves with the <strong>metadata<\/strong> in the yaml root, consisting of these valid\u00a0fields.<\/p>\n<p>name: A short name for your app that is readable by humans. e.g.\u00a0my-appversion: The ROFL version you are using. e.g.\u00a00.1.1repository: A path to the git repository. e.g. <a href=\"https:\/\/github.com\/user\/my-app\">https:\/\/github.com\/user\/my-app<\/a>author: The author name and the e-mail address. e.g., if you are John Doe, then it will show John Doe &lt;john@doe.com&gt;license: The ROFL license in <a href=\"https:\/\/spdx.org\/licenses\/\">SPDX<\/a> format. e.g. Apache-2.0tee: The Trusted Execution Environment type that is being used. tdx is the default option, while sgx is also\u00a0valid.kind: As outlined in the initialization process of the <a href=\"https:\/\/medium.com\/coinmonks\/roflize-an-app-part-1-rofl-workflow-to-initialization-65ed1fad7781\">workflow<\/a>. Valid options for TDX TEE are containers, which is the default, or raw. If you use SGX TEE, then only raw is the valid\u00a0option.<\/p>\n<p><strong>App Resources (<\/strong><strong>resources)<\/strong><\/p>\n<p>Each containerized app running in ROFL needs pre-defined resources such as the number of assigned vCPUs, amount of memory, storage requirements, GPUs, etc, for its execution. In the app manifest file, these will be headed under resources.<\/p>\n<p>resources:<br \/>  memory: 512<br \/>  cpus: 1<br \/>  storage:<br \/>    kind: disk-persistent<br \/>    size: 512<\/p>\n<p>If you decide to change the requested resources, it will result in the creation of a different enclave identity for the app. Then you will have to update the policy accordingly.<\/p>\n<p>Let\u2019s now see what these resources signify.<\/p>\n<p><strong>Memory (<\/strong><strong>memory)<\/strong><br \/> The amount of memory is specified in megabytes. It is initialized to 512 by\u00a0default.<strong>vCPU Count (<\/strong><strong>cpus)<\/strong><br \/> The number of vCPUs allocated to the VM. It is initialized to 1 by\u00a0default.<strong>Storage (<\/strong><strong>storage)<\/strong><br \/> You can choose different storage options for your ROFL app based on its utility. Currently, it can be one of four\u00a0options.disk-persistent: When the disk of the given size is persistent, it is encrypted and authenticated using a key derived by the decentralized on-chain key management system after successful attestation. This is what our example\u00a0shows.disk-ephemeral: When the disk of the given size is ephemeral, it is encrypted and authenticated using an ephemeral key randomly generated on each\u00a0boot.ram: Here, an ephemeral filesystem is entirely contained in encrypted memory.none: Here, no storage provision has been made. This option is not valid for containerized apps, so you have to choose one of the previous\u00a0three.<\/p>\n<p>The size field defines the amount of storage to provision in megabytes.<\/p>\n<p><strong>Artifacts (<\/strong><strong>artifacts)<\/strong><\/p>\n<p>This configures locations of artifacts used during the ROFL build process with builder, firmware, kernel, stage2, container.runtime, and container.compose as supported fields. If any fields are left unspecified, they will use the default artifacts from the CLI. For containerized apps, container.compose points to the Compose file included in the ROFL\u00a0bundle.<\/p>\n<p>artifacts:<br \/>  container:<br \/>    compose: compose.yaml<\/p>\n<p><strong>Deployments (<\/strong><strong>deployments)<\/strong><\/p>\n<p>This contains ROFL deployments on specific networks.<\/p>\n<p>The deployment you have defined will show as deployment_name.<\/p>\n<p>Deployment artifacts are optional and merged field by field on top of global artifacts.<\/p>\n<p>deployments:<br \/>  testnet:<br \/>    network: testnet<br \/>    paratime: sapphire<br \/>    artifacts:<br \/>      container:<br \/>        compose: compose.testnet.yaml<\/p>\n<p>There are four components to policy under which your app will spin\u00a0up.<\/p>\n<p>quotes: Include TEE-specific policy requirements such as the TCB validity period and the minimum TCB-R number. This helps to indicate what security updates must be applied to the given platform.enclaves: Include permissioned enclave IDs for running your\u00a0app.endorsements: Include a list of conditions defining who can run the\u00a0app.any: {} indicates any node can run the\u00a0app.node: &lt;node_id&gt; indicates only a specified node ID can run the\u00a0app.provider: &lt;address&gt; indicates nodes belonging to the specified ROFL provider can run the\u00a0app.provider_instance_admin: &lt;address&gt; indicates machines having the specified admin can run the\u00a0app.<\/p>\n<p>You can choose one or multiple conditions in a nested format by using and and or operators.<\/p>\n<p>policy.yaml<\/p>\n<p>endorsements:<br \/>  &#8211; and:<br \/>    &#8211; provider: oasis1qp2ens0hsp7gh23wajxa4hpetkdek3swyyulyrmz<br \/>    &#8211; or:<br \/>      &#8211; provider_instance_admin: oasis1qrk58a6j2qn065m6p06jgjyt032f7qucy5wqeqpt<br \/>      &#8211; provider_instance_admin: oasis1qqcd0qyda6gtwdrfcqawv3s8cr2kupzw9v967au6<\/p>\n<p>This example indicates that the app can be run only on the specified provider, and on machines owned by either of the two admin addresses.<\/p>\n<p>fees: &lt;fee_policy&gt; specifies who pays for the registration and other fees. It can be either endorsing_node when the node running the app pays, or instance when the app instance\u00a0pays.<\/p>\n<p>The final piece of this section is machines, where the specific app deployment takes place. If you remember the <a href=\"https:\/\/medium.com\/coinmonks\/roflize-an-app-part-2-create-build-deploy-test-096900eb3ead\"><strong>oasis rofl deploy<\/strong><\/a> tutorial, it creates a new default machine if there is no existing machine. If there is one, then the app is redeployed here.<\/p>\n<p>&lt;machine_name&gt; is the name you choose for the\u00a0machine.provider: &lt;provider_address&gt; is the Oasis native address of the ROFL provider hosting the\u00a0machine.offer: &lt;offer_name&gt; specifies what offer you have\u00a0chosen.id: &lt;machine_id&gt; is the ID of the machine per provider.permissions are optional, and when present, indicate ROFL scheduler-specific permissions.log.view will list all the Oasis native addresses that can access machine\u00a0logs.<\/p>\n<h3>appd REST\u00a0API<\/h3>\n<p>Each containerized app running in ROFL runs a special daemon called rofl-appd. It exposes additional functions via a simple HTTP REST API. To enable easier access isolation, the API is exposed via a UNIX socket located at \/run\/rofl-appd.sock.<\/p>\n<p>Let\u2019s consider this example where we have used the <a href=\"https:\/\/docs.docker.com\/reference\/compose-file\/services\/#short-syntax-5\">short syntax for Compose\u00a0volumes<\/a>.<\/p>\n<p>services:<br \/>  mycontainer:<br \/>    # &#8230; other details omitted &#8230;<br \/>    volumes:<br \/>      &#8211; \/run\/rofl-appd.sock:\/run\/rofl-appd.sock<\/p>\n<p><strong>ROFL clients<\/strong><\/p>\n<p>For your ROFL app, it is strongly recommended that you follow the steps to bind the UNIX socket by accessing the ROFL REST API through one of the ROFL clients. You can choose any one of the following languages.<\/p>\n<p>oasis-rofl-client for\u00a0<a href=\"https:\/\/pypi.org\/project\/oasis-rofl-client\/\">Python<\/a>@oasisprotocol\/rofl-client for <a href=\"https:\/\/www.npmjs.com\/package\/@oasisprotocol\/rofl-client\">TypeScript<\/a>oasis-rofl-client for\u00a0<a href=\"https:\/\/github.com\/oasisprotocol\/oasis-sdk\/tree\/main\/rofl-client\/rs\">Rust<\/a><\/p>\n<p>Note: Although the communication with rofl-appd is through UNIX sockets, the REST service still uses the HTTP protocol. In our examples, we will be using the http:\/\/localhost\/&lt;endpoint_path&gt; format throughout. You are free to provide any name instead of a hostname.<\/p>\n<p><strong>Endpoints<\/strong><\/p>\n<p><strong>App Identifier<\/strong> is where the endpoint is used to retrieve the app ID.<br \/>Endpoint:\/rofl\/v1\/app\/id ( GET)<br \/>Example response:<\/p>\n<p>rofl1qqn9xndja7e2pnxhttktmecvwzz0yqwxsquqyxdf<\/p>\n<p><strong>Key Generation<\/strong><\/p>\n<p>Here, each registered app automatically gets access to a decentralized on-chain key management system. Now, the keys can only be generated inside properly attested app instances. They remain unchanged even if the app is deployed elsewhere, or even if its state is erased.<br \/>Endpoint:\/rofl\/v1\/keys\/generate ( POST)<br \/>Example\u00a0request:<\/p>\n<p>{<br \/>  &#8220;key_id&#8221;: &#8220;demo key&#8221;,<br \/>  &#8220;kind&#8221;: &#8220;secp256k1&#8221;<br \/>}key_id is used for domain separation of different keys. It is a unique identifier, with every key ID corresponding to a different key.kind defines what kind of key should be generated. Options\u00a0include:raw-256 to generate 256 bits of\u00a0entropyraw-386 to generate 384 bits of\u00a0entropyed25519 to generate an Ed25519 private\u00a0keysecp256k1 to generate a Secp256k1 private key, as used in our\u00a0example<\/p>\n<p>The generated key is returned as a hexadecimal string.<br \/> Example response:<\/p>\n<p>{<br \/>  &#8220;key&#8221;: &#8220;a54027bff15a8726b6d9f65383bff20db51c6f3ac5497143a8412a7f16dfdda9&#8221;<br \/>}<\/p>\n<p><strong>Authenticated Transaction Submission<\/strong><\/p>\n<p>This is important if your app is registered with a different chain instead of Oasis. It enables your ROFL app to submit authenticated transactions to that chain. As these transactions are signed by an <strong>endorsed ephemeral key<\/strong>, they get automatically authenticated.<\/p>\n<p>This also helps to easily authenticate the transaction origin in smart contracts by simply invoking an <a href=\"https:\/\/api.docs.oasis.io\/sol\/sapphire-contracts\/contracts\/Subcall.sol\/library.Subcall.html#roflensureauthorizedorigin\">appropriate subcall<\/a>.<\/p>\n<p>Subcall.roflEnsureAuthorizedOrigin(roflAppID);<\/p>\n<p>Endpoint: \/rofl\/v1\/tx\/sign-submit (POST)<br \/>Example:<\/p>\n<p>{<br \/>  &#8220;encrypt&#8221;: true,<br \/>  &#8220;tx&#8221;: {<br \/>    &#8220;kind&#8221;: &#8220;eth&#8221;,<br \/>    &#8220;data&#8221;: {<br \/>      &#8220;gas_limit&#8221;: 200000,<br \/>      &#8220;to&#8221;: &#8220;1234845aaB7b6CD88c7fAd9E9E1cf07638805b20&#8221;,<br \/>      &#8220;value&#8221;: &#8220;0&#8221;,<br \/>      &#8220;data&#8221;: &#8220;dae1ee1f00000000000000000000000000000000000000000000000000002695a9e649b2&#8221;<br \/>    }<br \/>  }<br \/>}<\/p>\n<p>Let\u2019s decipher the fields before proceeding further.<\/p>\n<p>tx describes the transaction content. Different transaction kinds are supported as defined by the kind\u00a0field.<\/p>\n<p>Ethereum-compatible calls ( eth) use standard fields such as gas_limit, to, value, and\u00a0data.<\/p>\n<p>For gas_limit, you can input a JSON number (as used in the example), a decimal string, or a 0x-prefixed hex string. There should not be any whitespace, and irrespective of the input, it will be interpreted as a non-negative 64-bit\u00a0integer.<\/p>\n<p>For value, you can input a JSON number up to 2^64 &#8211; 1, a decimal string, or a 0x-prefixed hex string. There should not be any whitespace in the string forms, and the value must represent a non-negative integer up to 256\u00a0bits.<\/p>\n<p>For hex-encoded fields such as to and data, you can input strings with or without a leading 0x prefix, but there should not be any whitespace or prefix-only input. Empty strings are accepted for contract creation or empty calldata, e.g. to: &#8220;&#8221; or data: &#8220;&#8221;. If you are providing input for the to field, it must decode to exactly 20 bytes representing an Ethereum\u00a0address.<\/p>\n<p>Alternately, Oasis SDK calls ( std) support CBOR-serialized hex-encoded Transactions to be specified.<\/p>\n<p>encrypt is a boolean flag specifying whether the transaction should be encrypted. This field is true by default. When an ephemeral key is being used, the encryption is handled transparently for the caller, and any response is first decrypted before being passed\u00a0on.<\/p>\n<p>Now, as the outcome of the example request, the example response inside data is generated as a JSON response containing a CBOR-serialized hex-encoded <a href=\"https:\/\/api.docs.oasis.io\/rust\/oasis_runtime_sdk\/types\/transaction\/enum.CallResult.html\">call result<\/a> that you will need to deserialize.<\/p>\n<p>If the call result is successful:<\/p>\n<p>{<br \/>  &#8220;data&#8221;: &#8220;a1626f6b40&#8221;<br \/>}<\/p>\n<p>It deserializes as {&#8220;ok&#8221;:\u00a0&#8221;}.<\/p>\n<p>If it is unsuccessful:<\/p>\n<p>{<br \/>  &#8220;data&#8221;: &#8220;a1646661696ca364636f646508666d6f64756c656365766d676d6573736167657272657665727465643a20614a416f4c773d3d&#8221;<br \/>}<\/p>\n<p>It deserializes as {&#8220;fail&#8221;: {&#8220;code&#8221;: 8, &#8220;module&#8221;: &#8220;evm&#8221;, &#8220;message&#8221;: &#8220;reverted: aJAoLw==&#8221;}}.<\/p>\n<p><strong>Replica Metadata<\/strong><\/p>\n<p>This allows apps to publish arbitrary key-value pairs included in the on-chain ROFL replica registration and automatically namespaced with net.oasis.app.<\/p>\n<p><strong>Get Metadata<\/strong>: With this, you can retrieve all user-set metadata key-value pairs.<\/p>\n<p>Endpoint: \/rofl\/v1\/metadata (GET)<br \/>Example response:<\/p>\n<p>{<br \/>  &#8220;key_fingerprint&#8221;: &#8220;a54027bff15a8726&#8221;,<br \/>  &#8220;version&#8221;: &#8220;1.0.0&#8221;<br \/>}<strong>Set Metadata<\/strong>: With this, you can set metadata key-value pairs to replace all existing app-provided metadata.<\/p>\n<p>Endpoint: \/rofl\/v1\/metadata (POST)<br \/>Example\u00a0request:<\/p>\n<p>{<br \/>  &#8220;key_fingerprint&#8221;: &#8220;a54027bff15a8726&#8221;,<br \/>  &#8220;version&#8221;: &#8220;1.0.0&#8221;<br \/>}<\/p>\n<p>The parameters for metadata validation are the number of pairs, key size, and value\u00a0size.<\/p>\n<p><strong>Upsert Metadata<\/strong>: With this, you can input or update metadata key-value pairs. However, if you did not specify it in your request but there is existing app metadata, that will not be affected.<\/p>\n<p>Endpoint: \/rofl\/v1\/metadata (PUT)<br \/>Example\u00a0request:<\/p>\n<p>{<br \/>  &#8220;version&#8221;: &#8220;1.0.1&#8221;<br \/>}<strong>Delete Metadata<\/strong>: With this, you can delete given metadata keys, while keys that no longer exist will be\u00a0skipped.<\/p>\n<p>Endpoint: \/rofl\/v1\/metadata (DELETE)<br \/>Example\u00a0request:<\/p>\n<p>[&#8220;version&#8221;, &#8220;key_fingerprint&#8221;]<\/p>\n<p>Whenever you use Set, Upsert, or Delete Metadata, any change in the metadata triggers a registration refresh.<\/p>\n<p><strong>Query<\/strong><\/p>\n<p>This runs arbitrary query methods defined in the <a href=\"https:\/\/github.com\/oasisprotocol\/oasis-sdk\/tree\/main\/runtime-sdk\">Oasis Runtime SDK<\/a> module and returns the\u00a0result.<\/p>\n<p>Endpoint: \/rofl\/v1\/query (POST)<br \/>Example\u00a0request:<\/p>\n<p>{<br \/>  &#8220;method&#8221;: &#8220;rofl.App&#8221;,<br \/>  &#8220;args&#8221;: &#8220;a16269645500694cb01f85408d624ea267f657bf285787a61db3&#8221;<br \/>}<\/p>\n<p>Here, method refers to the internal name of query methods; in our example, it is <a href=\"https:\/\/github.com\/oasisprotocol\/oasis-sdk\/blob\/394da333625a189abd8b752a9f2dc46bb883a781\/runtime-sdk\/src\/modules\/rofl\/mod.rs#L647\">rofl.App<\/a>. You will recognize query methods by the #[handler(query = &#8220;&#8230;&#8221;)] annotation in the Oasis Runtime SDK source.<br \/>args represent query parameters for the method serialized as CBOR and hex-encoded.<\/p>\n<p>Example response:<\/p>\n<p>{&#8220;data&#8221;:&#8221;a76269645500ffe981cceff2d759d19fa926faebb7d90c0a59a56373656b582056c6d4841fa5ad24ad761088cb7053ad312ef13f3c2f405640fdba2bde4c14386561646d696e55007814f3d954f41b6459eb9e4bc8fbc6767ece5aa9657374616b658249056bc75e2d631000004066706f6c696379a56466656573026671756f746573a263696173f663706373a363746478a173616c6c6f7765645f7464785f6d6f64756c657380737463625f76616c69646974795f706572696f64181e781e6d696e5f7463625f6576616c756174696f6e5f646174615f6e756d6265721268656e636c6176657382a2696d725f7369676e6572582000000000000000000000000000000000000000000000000000000000000000006a6d725f656e636c6176655820bd4844a79a12ba365e890ddeaebbc4e4292797c7d956b42c2e25e4aefce3b124a2696d725f7369676e6572582000000000000000000000000000000000000000000000000000000000000000006a6d725f656e636c6176655820412c94a9baa0949f718dbba41ab89c38ea5c320345bba36b07e2ef857ffe2fb96c656e646f7273656d656e747381a163616e79a06e6d61785f65787069726174696f6e036773656372657473a26a50494e4154415f4a5754590327a462706b58207f88546291174f854a8ce2eb4bbfc8e62e40d60cdae2d600920a766d3006bf6c646e616d65581aad0460d0f742ad697b6d7c8462cc2b153deeb051a791553ef52b656e6f6e63654f8cbbe6631910d9a702e49bd30ee8f46576616c75655902c1352d823e54f75c846579066e2c1a750387f0630e3f29dba5524984712883bb33371ff017e507ae432b135312af64bfb85f3b17def05b2ac2744256f5accf1a26b29cd8cd412f08bfc9204f9bfa670b2d65972cfc4a8d4e2074402f21c18dfe554b1f0a8a731c077699f741807b3a4047ef4dc570958b8b46111a445259e93c9b92a5f72a23d32cbbef875efe586a8ddda38f1fa286d19b369a2022c3eae1cdbf6f6de4dc055bbab36a2c4830f8e2c64437f5f878f419e21f3a4c0f13c47b63697668b34722eaa61bdffa12e82be6d0266a41590254c9d70e9237475f6115c2867065c49afa8032acdfe0bc5dc671ef48ebc58d893937659243479e2eaa38815cd8665541e4c7e40349524cda15f2d410cba100ee27f0a59dc63534f7cff2444b57c7b74060cf8c3e21e1590b597384a89a463d6bb4a52fc52a4592889448a8f8e0c02fef1689c1efea58ddc08783f6d22d7a908cdf2a45bc46a79a3b73ff5f13bbbf7219973a7382eee84b3b4d48036b5e87fb24223e6387a3e37f9c1ac9722534adfef0201ec13db2e70fe9cd0336f020e50b59d7d32951378f568a4ef3a8117386ff0f1ba4b7d33dcf913daa696a6a7d64d20220b0e5eec994ea56aa9c01f56f5e12bf7d555b3f4a218ddbd8ae1586d5cb1e76802c90e26472b233686e8449284829378163acd77d1b65d4953a76cc497584580c1a5ac4fe6d97fd818fa53c2eb43c6f1b7a79211ef57f24036b1f8ed37f4c3d36873bbbd876769a5fde17add6926317afc96c9707e10b150735c63877ffd6475b1a27b6dd108940f0097375e422b1d308c6c8a0a83847368f5760778c54f2a70b44f9365c55c4b5d69341cad62d6fdb11aa25a9e26b4977adebd65718042bda1cbbf988298d293547107c2f5899352188179bc4d22febc66e8e351885498e707dee583d052c0b7c13f930e4529b59c36c20ee3ee6d29d1a3e2bb65bd489b7206cd45d2ae046f1e147d6407c166e494e465552415f4150495f4b45595899a462706b582074be2e227be81a5e35943ac1b79e238395b9bc367f7a0d1eed740c259ae23a37646e616d65581ee5190cda87688753f6f221890bfed8fe0e27b3ced4a9bc54537da1f4cd90656e6f6e63654fcf5411193abf4f4711f17179ea4b6f6576616c756558304675a29c8398bc94b5057063b4badeb9937a6e019ef7f8095d6b5a035106d4e8e7d710af9b6883848886481c1d180cbc686d65746164617461a7736e65742e6f617369732e726f666c2e6e616d656f76616c696461746f722d6167656e74756e65742e6f617369732e726f666c2e617574686f72782a4d61746576c5be204a656b6f766563203c6d617465767a406f6173697370726f746f636f6c2e6f72673e766e65742e6f617369732e726f666c2e6c6963656e73656a4170616368652d322e30766e65742e6f617369732e726f666c2e76657273696f6e65302e312e30776e65742e6f617369732e726f666c2e686f6d6570616765784f68747470733a2f2f6769746875622e636f6d2f6f6173697370726f746f636f6c2f6572632d383030342f626c6f622f6d61737465722f524541444d452e6d642376616c696461746f722d6167656e7478196e65742e6f617369732e726f666c2e7265706f7369746f7279782968747470733a2f2f6769746875622e636f6d2f6f6173697370726f746f636f6c2f6572632d38303034781a6e65742e6f617369732e726f666c2e6465736372697074696f6e787f4c697374656e7320746f2056616c69646174696f6e52657175657374206576656e7473206f6620746865204552432d383030342076616c69646174696f6e20726567697374727920616e642076616c696461746573207768657468657220746865206167656e7420697320706f776572656420627920524f464c205445452e&#8221;}<\/p>\n<p>Inside data, the JSON response contains the CBOR-serialized method&#8217;s return value in hex\u00a0format.<\/p>\n<p>If you want to try other examples, you can check out the <a href=\"https:\/\/github.com\/oasisprotocol\/demo-rofl\/blob\/ab7e60aeb5f10aaec0a5f401086b2ba259a30107\/docker\/app.sh#L9-L18\">relevant section<\/a> of the ROFL demo repository for querying with curl directly.<br \/> There is also a production-ready Python example at hand\u200a\u2014\u200ain the <a href=\"https:\/\/github.com\/oasisprotocol\/erc-8004\/blob\/18f8630f7397ec889ea55b008391664f3b736128\/rofl-8004\/rofl_metadata.py#L47\">ROFL-8004 implementation<\/a> where the query endpoint is used to fetch various app on-chain metadata for registration in the <a href=\"https:\/\/eips.ethereum.org\/EIPS\/eip-8004#identity-registry\">ERC-8004 identity registry<\/a>.<\/p>\n<h3>Port Proxy<\/h3>\n<p>When you publish a port in your compose.yaml file, the ROFL proxy automatically makes your services accessible via public URLs. It also ensures the routed traffic is done correctly.<\/p>\n<p>This uses TLS, which is terminated inside your ROFL enclave, maintaining confidentiality and integrity protection. As a result, even the provider cannot see or modify the traffic. Moreover, the default terminate-tls mode generates and configures a Let&#8217;s Encrypt certificate in ROFL to authenticate your services.<\/p>\n<p>To enable the proxy and expose a port from your container, you need to publish it in your compose.yaml file.<\/p>\n<p>compose.yaml<\/p>\n<p>services:<br \/>  frontend:<br \/>    image: docker.io\/hashicorp\/http-echo:latest<br \/>    ports:<br \/>      &#8211; &#8220;5678:5678&#8221; # Expose container port 5678 on host port 5678<\/p>\n<p>After deploying your app, you can find the generated URL by running the usual\u00a0command.<\/p>\n<p>oasis rofl machine show<\/p>\n<p>The output generated in this way will show a Proxy section with the public URL for each published port.<\/p>\n<p>Proxy:<br \/>  Domain: m602.test-proxy-b.rofl.app<br \/>  Ports from compose file:<br \/>    5678 (frontend): https:\/\/p5678.m602.test-proxy-b.rofl.app<\/p>\n<p><strong>Configuration<\/strong><\/p>\n<p>You can use the <a href=\"https:\/\/docs.docker.com\/reference\/compose-file\/services\/#annotations\">annotations<\/a> in your compose.yaml file to configure the proxy behavior.<\/p>\n<p>The general format of an annotation is net.oasis.proxy.ports.&lt;published_port&gt;.&lt;setting&gt;: &lt;value&gt;.<br \/> Here,&lt;published_port&gt; is the external port exposed in your compose.yaml, and &lt;setting&gt; indicates the specific proxy configuration like mode or custom_domain.<\/p>\n<p>Example:<br \/>Here I will configure port 80 to use the default terminate-tls mode with a custom domain and port 8080 to use TCP passthrough.<\/p>\n<p>compose.yaml<\/p>\n<p>services:<br \/>  myservice:<br \/>    image: docker.io\/my\/service:latest<br \/>    ports:<br \/>      &#8211; &#8220;80:80&#8221;<br \/>      &#8211; &#8220;8080:8080&#8221;<br \/>    annotations:<br \/>      net.oasis.proxy.ports.80.custom_domain: mydomain.com<br \/>      net.oasis.proxy.ports.8080.mode: passthrough<\/p>\n<p>This shows:<\/p>\n<p>The application container exposes ports 80 and\u00a08080.On port 80, the proxy terminates TLS for mydomain.com and forwards traffic to the application container.On port 8080, the proxy forwards the raw TCP connection to your application container (mode: passthrough).<\/p>\n<p><strong>Annotation Reference<\/strong><\/p>\n<p>net.oasis.proxy.ports.&lt;published_port&gt;.mode defines how the proxy should handle connections for the specified port.<\/p>\n<p>net.oasis.proxy.ports.&lt;published_port&gt;.custom_domain assigns a custom domain name to the published port.<\/p>\n<p>Here, when using the default terminate-tls mode, you need to use special configuration for your custom domain to route through the proxy. Once the app is deployed, you can use Oasis CLI for instructions to configure A and TXT records in your\u00a0DNS.<\/p>\n<p>oasis rofl machine showProxy:<br \/>  Domain: m897.opf-testnet-rofl-25.rofl.app<br \/>  Ports from compose file:<br \/>    5678 (frontend): https:\/\/demo.rofl.build<br \/>      * Point the A record of your domain to: 131.153.241.25<br \/>      * Add a TXT record to your domain:<br \/>oasis-rofl-verification=4SKHCn4E2SNDB5tXayQeHZsvH\/+kJSNGuQaTAPepYJc=<\/p>\n<p>If you choose to go with passthrough mode, the proxy will not terminate TLS and your app will then need to handle it directly. Also, here the custom_domain setting is not needed, so you can configure the domain directly to the ROFL instance&#8217;s address.<\/p>\n<p>For the ignore mode, the port isn&#8217;t published, so the custom_domain setting has no\u00a0effect.<\/p>\n<h3>Troubleshooting<\/h3>\n<p>Here I will cover some common errors and the troubleshooting process.<\/p>\n<p><strong>Compilation<\/strong><\/p>\n<p>Sometimes you will see an error message if the aes and ssse3 compiler flags are not enabled during compilation of your SGX and TDX-raw\u00a0ROFL.<\/p>\n<p>error: The following target_feature flags must be set: +aes,+ssse3.<br \/>&#8211;&gt; \/home\/user\/.cargo\/registry\/src\/index.crates.io-6f17d22bba15001f\/deoxysii-0.2.4\/src\/lib.rs:26:1<br \/>|<br \/>26 | compile_error!(&#8220;The following target_feature flags must be set: +aes,+ssse3.&#8221;);<br \/>| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<\/p>\n<p>The workaround is to add default flags to your\u00a0.cargo\/config.toml file.<\/p>\n<p>[build]<br \/>rustflags = [&#8220;-C&#8221;, &#8220;target-feature=+aes,+ssse3&#8221;]<br \/>rustdocflags = [&#8220;-C&#8221;, &#8220;target-feature=+aes,+ssse3&#8221;]<\/p>\n<p>[test]<br \/>rustflags = [&#8220;-C&#8221;, &#8220;target-feature=+aes,+ssse3&#8221;]<br \/>rustdocflags = [&#8220;-C&#8221;, &#8220;target-feature=+aes,+ssse3&#8221;]<\/p>\n<p><strong>Compose file<\/strong><\/p>\n<p>A couple of errors are possible here due to an upstream <a href=\"https:\/\/github.com\/containers\/podman-compose\/issues\/264\">podman compose\u00a0bug<\/a>.<\/p>\n<p>The first is when environment variables defined are not considered.<\/p>\n<p>services:<br \/>  oracle:<br \/>    platform: linux\/amd64<br \/>    environment:<br \/>      CONTRACT_ADDRESS: 0x5FbDB2315678afecb367f032d93F642f64180aa3<br \/>    entrypoint: \/bin\/sh -c &#8216;python main.py $${CONTRACT_ADDRESS}&#8217;<\/p>\n<p>In this type of error, the CONTRACT_ADDRESS field will return as empty in ROFL. You need to inject the variable value directly inside entrypoint as a workaround.<\/p>\n<p>services:<br \/>  oracle:<br \/>    platform: linux\/amd64<br \/>    entrypoint: \/bin\/sh -c &#8216;python main.py 0x5FbDB2315678afecb367f032d93F642f64180aa3&#8217;<\/p>\n<p>The other type of error that may occur is when depends_on is\u00a0ignored.<\/p>\n<p>services:<br \/>  contracts:<br \/>    image: &#8220;ghcr.io\/foundry-rs\/foundry:latest&#8221;<br \/>    platform: linux\/amd64<br \/>    volumes:<br \/>      &#8211; .\/contracts:\/contracts<br \/>    entrypoint: \/bin\/sh -c &#8216;cd contracts &amp;&amp; forge create&#8217;<\/p>\n<p>  oracle:<br \/>    platform: linux\/amd64<br \/>    entrypoint: \/bin\/sh -c &#8216;python main.py&#8217;<br \/>    restart: on-failure<br \/>    depends_on:<br \/>      contracts:<br \/>        condition: service_completed_successfully<\/p>\n<p>In this type of error, instead of oracle spinning up once the contracts service successfully deploys the contracts and finishes, they start in parallel by ignoring the depends_on command.<\/p>\n<p>There is no immediate workaround as of now. You can try to implement customized logic in your oracle service to crash it, and then trigger the restart mechanism and try\u00a0again.<\/p>\n<p><strong>appd<\/strong><\/p>\n<p>If you encounter the 422 Unprocessable Entity error, when the provided request couldn&#8217;t be decoded, you need to ensure all the required fields are present and correctly formatted in accordance with the <strong>appd REST API<\/strong> section described above.<\/p>\n<p><strong>ROFL Proxy URL is not\u00a0working<\/strong><\/p>\n<p>Sometimes the app might be using outdated artifacts, which will result in the proxy URL returned by oasis rofl machine show being inaccessible. This is easily fixed by updating to the latest Oasis CLI version. The next step is to run oasis rofl upgrade in your project directory to update the artifacts in your rofl.yaml file, and finally, rebuild and redeploy your\u00a0app.<\/p>\n<p>oasis rofl build<br \/>oasis rofl update<br \/>oasis rofl deploy<\/p>\n<p>This concludes our 2-part bonus guide describing the various features for your ROFL app, and some common troubleshooting hacks. Looking forward to your feedback in the comments\u00a0section.<\/p>\n<p>For technical specs, APIs, architecture, and integration guides, the <a href=\"https:\/\/docs.oasis.io\/\"><strong>Oasis documentation<\/strong><\/a> is your starting point.<br \/> For direct support on specific issues, the Oasis engineering team is available in the<a href=\"https:\/\/discord.com\/invite\/BQCxwhT5wS\"><strong>dev-central channel<\/strong><\/a> on the official\u00a0Discord.<\/p>\n<p><em>Originally published at <\/em><a href=\"https:\/\/dev.to\/dc600\/roflize-an-app-bonus-guide-to-features-troubleshooting-part-2-2j2c\"><em>https:\/\/dev.to<\/em><\/a><em> on August 14,\u00a02026.<\/em><\/p>\n<p><a href=\"https:\/\/medium.com\/coinmonks\/roflize-an-app-bonus-guide-to-features-troubleshooting-part-2-9cd921c283bc\">ROFLize an App: Bonus Guide to Features &amp; Troubleshooting (Part 2)<\/a> was originally published in <a href=\"https:\/\/medium.com\/coinmonks\">Coinmonks<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>In this 2-part bonus guide on the features and troubleshooting once you ROFLize an app, the first part covered in detail the marketplace, secrets, and persistent storage. Let\u2019s continue. Public Variables You will remember that we learned about secrets for confidential values. But an app may also consist of containers that need to access non-sensitive [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":214416,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-214415","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-interesting"],"_links":{"self":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/214415"}],"collection":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=214415"}],"version-history":[{"count":0,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/214415\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/media\/214416"}],"wp:attachment":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=214415"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=214415"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=214415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}