# README

## TApps are designed for Web3

As is the case with all TApps, the TEA Party showcases the special features that are beyond the capabilities of other cloud based internet (web 2.0) applications. Instead of centralized server(s) hosting the app, the individual miners of the TEA network host TApps based solely on their own [hosting profitability](/z_glossary/hosting_profitability). The inherent decentralization that all TApps including the TEA Party share gives these apps even more unique features:

* They cannot be turned off by any centralized power. As long as there are a minimal number of miners hosting any particular application, it will continue to run forever.
* No one, including the host miner, can control or censor the content. The content is owned and protected by its creator's private key. A miner can choose to stop hosting the TApp, but it cannot selectively choose what content to show or hide.
* There's no free lunch. Every action that costs any computing resources needs to be paid by someone. In TEA Party's particular case, every message sent needs to be paid for. Additional charges also apply to store the message or to notify the recipient. For further information, read more about [where the messages are stored](/z_glossary/where_the_message_is_stored).

In order to get the features above, the underlying technical layer is very different from the existing cloud computing and blockchain tech stacks. It's a new tech stack that's based on recent technologies. However, the developers do not need to understand the complicated low level distributed system, they can build application **as if** it is still a centralized cloud computing architecture. This is the **charm of the TEA Project**.

The following sections will explain the cutting edge technologies used in the TEA Party. We hope explaining the underlying technologies and how they work together will help you make your own TEA applications (TApps).

## Three Major Parts

The full architecture of the TEA Project is complicated but there are only three majors parts where an application developer will be working. These three major parts all run in different locations just like the traditional 3-tier-architecture of cloud computing web apps.

### [Front-end](/z_glossary/front_end)

The front-end is typically a JS application (for webapps) or a mobile application (for mobile apps). But the front-end isn't dictated by TEA, and the developer can use whatever front-end they're comfortable with.

### [Back-end](/z_glossary/back_end_actor)

This WebAssembly code is running inside of a hosting node. The hosting node is a miner's computer which has a CML planted. It's similar to the server logic running in back-end servers or application servers in the traditional cloud computing architecture.

### [State Machine Actor](/z_glossary/state_machine_actor)

This WebAssembly code is running inside the state machine's [mini-runtime](/z_glossary/mini-runtime). It's equivalent to the stored procedure (SQL for example code) in the traditional 3-tier architecture's database.

## Three-tier architecture basic workflow

The above 3 components are directly mapped to the traditional [3-tier architecture](https://teaproject.medium.com/the-tapps-3-tier-decentralized-tech-stack-43d2872f609b) of a typical cloud computing application.

The basic workflow would look like this: (this example uses a web-based TApp)

* The user generates a user action in the front-end. The Javascript web client catches the user action, generates a web request, and sends it to the backend.
* The back-end receives the web request and runs the Tea Party back-end code (we call it the back-end actor) to handle anything that does not need the state machine (traditionally, this is referred to as a database). But when it needs to query or update a state in the state machine, it will need to generate a request to the state machine tier. These can be broken down into [queries](/z_glossary/queries) (will not change the state) and [commands](/z_glossary/commands) (potentially could change the state). Commands are typically called [txns](/z_glossary/txn) in the blockchain industry.
* The queries and commands are handled by the state machine replications. For queries, it will look up the local state and send the result back. For commands, as one of the replications, it should not modify on its own. Instead, it generates a txn and puts it in a global queue that we call the [conveyor](/z_glossary/conveyor). The replicas run a Proof of Time consensus to guarantee that all state machines in all replicas get the same [order\_of\_txns](/z_glossary/order_of_txns). This ensures that their state can always be kept identical after executing the command. This is the same methodology as is typically used by a distributed database system.

## Storage

There are three types of storage options for different use cases.

* [orbitdb](/z_glossary/orbitdb): Based on IPFS / used for large blob storage. It's running on the [hosting CML](/z_glossary/hosting_cml).
* [State](/z_glossary/state): Usually used to store account balance. It runs inside the [state machine](/z_glossary/state_machine).
* [gluesql](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/010_core_docs/gluesql.md): Distributed SQL server instances. It's located inside the [state machine](/z_glossary/state_machine).

## Comparison between the three storage options

| Storage options   | Relational?      | Cost | Consistency type     | Use cases in Tea Party                                      |
| ----------------- | ---------------- | ---- | -------------------- | ----------------------------------------------------------- |
| OrbitDb (on IPFS) | Non-relational   | Low  | Eventual consistency | Message body & attachments                                  |
| State             | Non-relational   | High | Strong consistency   | Account balance                                             |
| GlueSQL           | Relational (SQL) | High | Strong consistency   | Not yet in use but can be used in common SQL business logic |

## Comparison with a cloud webapp's 3-tier architecture

| User action                                                                             | step                               | Eth based dApps                                            | cloud webapp                                                                                                                                              | TEA project                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | Note                                                                                                                                                                                                                                                                                |
| --------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Clicks the app to start                                                                 | Start a web app                    | N/A                                                        | Go to a domain name, usually <https://yourapp.com>                                                                                                        | Click the app name in your TEA wallet, you'll receive a list of hosting CMLs. Click any of them                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Cloud webapp has a centralized http/https domain name, but TEA doesn't have such a centralized control. Every hosting miner are seperate from each other                                                                                                                            |
| Show the UI in the browser                                                              | Load front-end code in the browser | N/A                                                        | Download the [front end](/z_glossary/front_end) code (js/html/css) from a webserver                                                                       | Download the front end from IPFS or any decentralized storage                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | TEA doesn't have a traditional web server. The front-end code and all static resources are stored in IPFS or some other decentralized storage. User will use the CID (hash) as a key to load the front-end code directly in the browser                                             |
| Show dynamic content, such as list of all messages                                      | Query database                     | Any client to query the block state                        | Browser sends request to the back-end server, back-end server then queries database for data. Send data all the way back to the browser to show on the UI | Browser request to hosting CML. The [back end actor](/z_glossary/back_end_actor) handles the request and then sends a P2P request to [state machine replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/010_core_docs/state_machine_replica.md). [state\_machine\_actor](/z_glossary/state_machine_actor) queries the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/010_core_docs/state_machine.md) then sends the data all the way back to the [front end](/z_glossary/front_end)                                                                                                                                                                    | Depends on what type of content the UI queries. Some content can be directly queried from a hosting CML's local OrbitDB instance. Accounting information needs go to the state machine. The TEA project also provides a Glue SQL database if the data is stored in an SQL database. |
| Create or update dynamic content, such as post new messages or extend existing messages | Send command to modify state       | Send transaction to any ETH miner and wait for a new block | The same as above                                                                                                                                         | [front end](/z_glossary/front_end) sends command to the [back end actor](/z_glossary/back_end_actor). [back end actor](/z_glossary/back_end_actor) generates a transaction (or calls a command) and sends it to a [state machine replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/010_core_docs/state_machine_replica.md) via P2P. The statemachine replica puts this transaction into the [conveyor](/z_glossary/conveyor) and then waits a grace period until the sequence of transactions reaches a consensus between more than 50% of replicas. Then load this transaction to the [back end actor](/z_glossary/back_end_actor) to execute the transaction which will update the state | There are many state machine replicas that keep a consistent state among them. So the Proof of Time is required to sync between replicas.                                                                                                                                           |

## The requirements for building TApps

In this section, we'll list the knowledge and tools you'll need to build TApps.

### Tools

To build and run the demo locally, you'll need:

* A Mac or Linux machine.
* Docker and docker-compose installed.
* Rust compiler.
* Web browser.

After building your own TApp, you can try hosting it by launching your own mining node. A mining node is any type of TEA node with a CML planted in it. If you don't own a physical TEA machine, you can rent an Amazon Nitro VM which is TEA-compatible.

### Programming languages

The demo TEA Party app is written in the following languages:

* **Front-end** is written in JS and the Vue framework. But this is just what we chose for this example: the TEA Project is agnostic as far as front-ends.
* **Back-end and State machine actors** are written using Rust and then compiled to WebAssembly.

The TEA Project doesn't require the developer to use the Rust programming language. You can use any programming language that compiles to WebAssembly. But at this moment, in order to understand our existing demo code, you'll need to use the Rust langauge.

### Architecture knowledge

#### Layer2 without Rollups

The TEA Project is considered a layer2 solution, but it has been designed with completely different mindset in comparison with existing roll-up solutions. We focus on providing a trustable computing infrastructure, hence why there's \[no need to verify the computing results]\(The\_future\_and\_innovation\_of\_layer2.md#We Trust the Result by Verifying the Environment). This allows the dApps running on our infrastructure to run at full speed, similar to cloud computing.

#### Layer2 decoupled with layer1

TEA Project runs \[on top of different kinds of blockchains]\(The\_future\_and\_innovation\_of\_layer2.md#Layer1 Agnostic) interchangeably due to there being no rollup required. The layer 1 blockchain provides one of the three Roots of Trust, with the other two roots of trust coming from hardware.

#### Hardware

The TEA Project is very different from many other blockchain projects. TEA relies on two types of hardware in order to reach a special type of consensus:

* [tpm](/z_glossary/tpm).
* [gps](/z_glossary/gps).

Please click the above links to learn more about how and why the TEA Project uses these technologies.

If you just want to run the code in your local simulator, you don't need any of the above hardware. You can run our simulator using Docker to run a test environment.

If you want to host your application in a production environment, you'll need a TEA node. If you don't own one, the easiest way is to rent an Amazon Nitro VM.

## Code walk through

**TEA Party** is a demo Web3 app running on the TEA Project. To explore a walk through of the TEA Party application's sample code, please continue reading the [code walkthrough](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/010_core_docs/t-rust/obsidian/_gitbook-dev-docs/045_advanced_tapps/020_teaparty.md).


# Basic Concepts


# TEA Developer Prerequisites

## Prerequisites for Becoming a TApp Developer

If you're an existing web developer in the cloud computing world we refer to as web2, then you're pretty much already a TApp developer. TApp development doesn't require any blockchain or distributed system skillsets. You can make your TApp as if it's a traditional 3-tier web app (front end, back end, and database).

## Basic programming skillsets

* Rust language (entry level).
* (Optional) SQL if you want to use SQL as your database.
* (Optional) Javascript if you also work on the front-end.

## Knowledge not required but nice to have

### Solidity / smart contracts

We don't require Solidity or smart contract knowledge although the TEA system itself is partially based on blockchain technology. Your business logic runs on the WebAssembly runtime inside enclaves that have nothing to do with smart contracts. However, if you're going to write any blockchain bridge that connects to any public blockchain, you will need to write smart contracts on that chain. This is out of the scope of the TEA Project.

### Distributed systems

TEA Project is a distributed system but it's tried its best to isolate the complexity under the hood. You, as a TApp developer, don't need to have any skill or knowledge about distributed systems. However, if you happen to have such knowledge, you can easily understand a lot of design choices made by the TEA Project. Those design choices may look weird from a traditional non-distributed way of thinking.

In most cases, you can design as if you're making a centralized traditional web2 application. The TEA Project has done all the heavy lifting work to make your code run decentralized across all nodes. Not only technically, but also financially. Financially meaning that even without knowning each other, there are other players in this ecosystem (miners, investors, maintainers) willing to work together to keep the system running because of the TEA Project's token incentives.


# The TEA Economic Revolution for Developers

This article is probably the only non-technical document in our developer-oriented documentation. But I still want it to be here because it's totally focused on you, our developers. I would like to show you what the TEA economy and Web3 revolution means to you as a developer and what changes you'll experence in the coming years.

## To work or not to work, that is the question

I live in Silicon Valley, a place full of tech giants and startups, (and to be honest, also homeless and drug addictions). The biggest dilemma for most developers is whether they should work for a company or make a decent life on my ambitious open-source project?

On one hand, working as a software engineer with an established tech company is well paid, with earnings higher than most lawyers and doctors. The salary is a must-have to live comfortably in Silicon Valley, at least if you don't want to end up homeless. On the other hand, you might have a dream to build some really cool open-source projects but this might end up only earning some donations. This sounds too close to asking for "spare changes?" on the street.

Let's see how Web3 and TEA project can merge these two sides, allowing developers to earn from publishing their code either as standalone apps or as libraries for other developers to use.

## API-as-a-Service, you don't need to make a full application

Writing good code and running a successful start-up business are two different skillsets. In fact, running a successful business requires much different skillset than most developers have. This would require having business sense, marketing, networking etc. Simply writing killer code cannot make someone profitable in the current web 2.0 world. That's why most talented developers still have to get hired by one of the tech giants to make a living.

But what if simply writing an API could bring you profit? Yes, just an API, no need to develop a UI or front end: no business development, no backend server mentainance, and still be able to make money. Is it possible?

In web 2.0 no. In Web3 with the TEA project, yes!

This is called API-as-a-Service. Back in the year 2020, we made an early stage demo of the TEA Project. [In that demo](https://youtu.be/6GYwrITSfJo), we described a use case where Bob wrote a Tensorflow AI code and could make a profit without dealling with anything else. Bob does not need to host his code, and he doesn't need to find customers to load their data to run against his code. He simple uploads his code to the TEA Project, and someone will pay to use it. And he doesn't need to worry about someone else stealing his code because his code **doesn't** have to be open sourced.

## Micropayments and high scalability are key

TEA has an open tokenomics model where no one gets a free lunch. Any actions in the TEA network needs to be paid by someone. No one works for free! Miners get paid through every line of code that runs through their CPU/GPU/TPU, occupies RAM / hard disk space, or transfers data using their network. Developers get paid by every time their code is executed. Consumers need to pay for whatever service they receive. Those micropayments can be done at an extremely low cost. That is one of the major benefits of TEA's layer-2 solution. Compared with ETH, it's **almost** free, and extremely fast.

## Trust and security protect your profit

You don't have to open-source your project if you're uploading it to the TEA Project. Your code can be close-sourced if you don't need to be audited for security reasons. You only need to send your code to the TEA Project where it will be sent to a node's trusted enclave. Your code will be compiled there and run inside the enclave. No one can steal your code, and the execution environment can always be trusted. Any miner can host your code and run it; there's no need to send your code to your clients to run or to maintain a server on your own. All these aspects of the business are handled by the TEA Project. Your profit is protected and guaranteed once your code is selected for use.

## Web3 applications are composed of all these smaller API-as-a-Service modules

In web 2.0, you'll have to open-source your code as a library so that other developers can use it **for free or by donation** in their own project. The unfortunate fact is that open-source contributors earn much less than they possibly could by going the donation route. In the TEA Project, all these components are just API functions, running inside one or more mining machines. Applications don't **include** this code in its own binary, but directly **call** these APIs and are paid for its usage by the billing system. The code developer gets paid in TEA tokens from the billing system periodically.

## Pay by use is the new business model

Just like today's internet is a large set of links to different webpages hosted on different servers, Web3 applications would also consist of a bunch of links to different API calls underneath the facade of the app. The full application could be composed by thousands of those smaller components that are written by different developers. They're all **linked** instead of **included (as in open-source libraries)**. Pay by use becomes the new business model.

The model encourage developers to work on their own projects instead of feeling forced to join a big tech firm so that they can afford to live in comfortably. They can make a decent living without the hassle of running a **full** business. Simply write good code, join the TEA Project, and get paid. Enjoy your life and happy coding!


# The Future of Layer-2s

## Existing Blockchains Use Layer-2s for Scalability

Ever since Blockchain was invented, many projects have tried improving the technology to make blockchain run faster and cheaper. To make blockchains more scalable, there are two primary innovation paths:

* Increasing scalability through improving the consensus: PoW -> PoS and other Proof of Whatever.
* Increasing scalability through off-chain computation, i.e. a layer2.

![\_1\_Scaling](https://user-images.githubusercontent.com/86096370/170151337-7ae0cff9-0327-46bd-8134-9463a796ae34.png)

Improving consensus can only go so far as nodes inherently have to wait for each other to reach consensus while making allowances for Byzantine fault tolerance. That leaves layer2s as an area of focus for achieving scalability. Basically, a typical layer2 does the following:

* Collects and batches txns from layer1.
* Execute those txns off-chain in layer2.
* Send the result back to layer1.
* Layer1 runs some kind of verification, then accepts the result and updates the blockchain.

The main problems with layer2 are that:

* Each layer2 has to be tightly bundled with a specific layer1.
* Verification is not cheap (e.g., ZKP). Possible resolver could be created either through inventing a new algorithm (unlikely) or hardware acceleration (ASIC).

## A New Type of Layer2

Although layer2s seem like a promising start towards scaling blockchain, there is still room for improvement. Let's imagine a new, improved layer2 that is:

* Agnostic of any type of layer1. Many innovative layer2s are currently tied to specific blockchains giving them only niche applicability in context of the entire crypto ecosystem.
* Able to run above and across all major blockchains. If this new layer2 could run across any blockchain, then we have also solved another thorny problem currently in crypto, that of bridging funds from one chain to another.
* Able to verify results with minimal or even zero verification. Calls back to layer1 to verify the result are a bottleneck that incurs conventional consensus and its typical transaction fees. What if we could verify the result without involving layer1 at all?

## We Trust the Result by Verifying the Environment

One aspect of improving the layer2 experience is being able to verify the result of layer2 transactions while minimizing the involvement of layer1 during these verifications. It turns out that we can verify the result of layer2 transactions simply by verifying the environment in which the programming logic is run. For example, if I asked you to verify the correctness of 82986.862 x 916019.1128 = 76017551703.3, how would you go about doing it? Probably very few people would use pencil and paper to verify the result.

You could counter that a multiplication problem, while tedious to verify, is technically doable by hand. So let's try something harder like verifying that the Ln(99999255) = 18.42. Well, most of us would just pick up our phone and use the calculator or some kind of app and key in the problem. If the result shows correctly, you'll likely be confident that you've verified it successfully.

But hold on - how do you know the result of your calculator app was correct? Have you recalculated it manually? No, most likely you haven't. You're basically trusting the platform that Steve Jobs and his predecessors have built on the iPhone. Have you ever considered that this is blind trust?

But it's not completely blind trust because most of us trust hardware like an iPhone because we trust the environment. As a side note, that's why Apple no longer offers support for jailbroken iPhones because they no longer have control over the environment and can no longer guarantee a trustable execution platform. Whether it's an iPhone or it's a CASIO calculator, they're all widely mass-produced and reliable computation environments. If users were to run the same calculation across different iPhones or calculators they would see the same result.

Let's move one step further and assume the calculator app is another layer2 node. In what circumstances can you believe the result from this node without computing the result for yourself again? To ensure that this layer2 calculator node is trustable, we must ensure that:

* The integrity of that node can be remotely verified, i.e. the node is in a trustable state from the perspective of any app that wants to run there.
* There are several randomly selected nodes running the same task separately, and they all get the same result.

![\_Remote\_Node\_Attestation](https://user-images.githubusercontent.com/86096370/170151343-135f7428-e7b7-434f-80cb-a29ff5e60350.png)

In this type of environment, can we trust the results? Well, a skeptic might say there are still some corner cases where:

* All of the nodes get infected by some kind of virus but cannot be detected remotely, or
* Somehow the nodes can collude together and send the user the same wrong answer.

These are legitimate concerns, but if we can use technology to reduce the chances of this occurring to be negligible in real world conditions, this would still be tolerable for our layer2 mechanism. Car accidents happen all the time, yet we still drive, right?

Now you can see, instead of verifying the result by recalculate, we just trust the process. The process means

* The environment can be trusted (i.e. the calculation happens in a trusted environment, which can be a branded environment - Apple, Intel, Casio etc.)
* The input code and data are correct (i.e. hash of the data and code are verified).
* Multiple, randomly selected nodes (uncolludable) get the same result separately.

## Benefits of Switching to Verifying the Environment

### Verifying the Environment is Cost Effective

As we just showed, verifying a brand of a calculator is much easier than recalculating manually using pencil and paper. Even adding on the cost of multiple brands of calculators to run the same formula, it's still much cheaper than recalculating manually.

Now let's extend this "verify result by verifying the environment" methodology to our potential layer2 solution. Instead of verifying the rollup results from layer2, we just verify the integrity of the layer2 nodes and "blind" trust the result before putting it on the blockchain. This change will significantly reduce the cost and complexity of layer1 verifications.

### Layer1 Agnostic

Let's take things one step further. If the verification of the integrity of layer2 nodes can be done agnostically relative to any type of layer1, then this layer2 could possibly run on any kind of layer1. For example, we can have the same layer2 solution running on top of Ethereum, Polkadot, Cosmos, BSC... as long as the layer1 supports basic Turing-complete smart contracts. This can make the layer2 solution blockchain agnostic, running above and across all major blockchains.

### General-purpose Computing

Let's add one more major feature to this killer layer2 that we're building. Since this new layer2 is agnostic towards the underlying layer1, there's no limit on what kind of txns it can process. In our implementation, general-purpose computing would be available in this new layer2. In this case, we don't really care if the layer1 blockchain is Solidity-based EVM or Rust, Wasm, ink etc. That's totally irrelavent as our layer2 can run general-purpose functions which might be totally unrelated to the layer1 underneath. For example, you could run a Tensorflow task on layer2 without any problems, although we would never expect a Solidity smart contract to run Tensorflow.

### Cloud Computing as an Oracle

Since we can run general-purpose computing, running a cloud computing oracle in layer2 won't be hard. As long as the environment can be trusted, we can have a distributed cloud-based SQL database running on the layer2. That means using SQL to write a smart contract is no longer a dream!

## How Do We Do This? Using (Controversial) Hardware Integrity

Hardware integrity remote attestation has always been controversial. There will always be arguments between the pure cryptographic algorithm believers vs those who favor hardware trusted execution environments. The truth is there are always pros and cons with either approach. In my opinion, before we can find a perfect math solution, using hardware integrity remote attestation is always a cost-effective compromise solution.

Long before blockchain, hardware integrity remote attestation has been in the IT industry for decades. All cybersecurity engineers know that trusted computing technologies have been used in every computer and most phones. That's how Microsoft and Apple know that your computer is jailbroken or hacked by a boot virus. How it works is that all the hardware that their OS's run on have a trusted computing secure chip called a TPM to record the hashes of your hardware before the OS is loaded. They report those hashes to Microsoft and Apple and validate it there, which in practice is a form of centralized remote attestation. In the blockchain world, we do this all decentralzied, so we just use other nodes as remote attestors. They're randomly selected by a VRF in the layer1 blockchain to reduce the chance of collusion. All those remote attestors make their own decision seperately and report their decision back to the layer1 blockchain. A simple voting procedure stored in a smart contract will determine if a testee is trusted or not.

Besides trusted computing technology, TEE is also presently widely used in many companies: Intel SGX, ARM Trust zone. The only cons of TEE is that it's tightly bound to the CPU manufacturer which causes new kind of centralization. For example, Intel recently discontinued processors with SGX for the consumer market. If you were a project relying on Intel SGX, then Intel's decision meant that your CPU options for miners going forward just got much more expensive.

## Conclusion and Future of Layer2

I believe that the future of layer2 will be as a standalone general-purpose cloud computing oracle that runs on top of multiple blockchains. This would also mean that the majority of computing tasks could be better performed at a lower cost by moving them from layer1 to layer2. Because our new layer2 does not need any expensive ZKP when sending the result back to layer1, the overall cost is much lower. Since layer2 is verified trusted by layer1, there's no blockchain type of consensus needed, and the performance can match that of traditioanl cloud computing. In TEA Project, we benefit from the many advantages of hardware trust. We use the timestamp as directly received from GPS satelites to run a "Proof of Time" distributed state machine in our trusted layer2 nodes. This is similar to Google's Spanner database, but ours is fully decentralized. Therefore, TEA Project is a decentralized cloud computing platform that runs so-called TApps. TApps run like typical web apps or mobile apps, but there's no centralized application server or database server needed, as well as no domain name or Verisign certificates. They are unstoppable, unbreakable, and censorship free.


# What Makes a Web3 App?

Web3 apps mark a significant departure from the cloud-based internet apps that modern users are used to. Modern internet apps give users relative convenience in exchange for the utility they provide. The typical traits that internet apps share include the following:

1. They're hosted on central servers. Even if the server architecture is distributed it's still owned by centralized companies.
2. These internet apps are often free to use and if not totally free, have a generous free tier.
3. The service provider has control of any user data that's given up to use the service.

In contrast, a Web3 app runs decentralized on a distributed architecture that nobody owns. An implication of this design is that a dApp can't be turned off by any centralized power. This means that a hosting miner can't censor any content in the dApp, they can only choose to stop hosting the entire dApp. And because no user data is given up to use a dApp, app usage is paid directly by the consumer in the world of Web3.

Let's take a closer look at each of these differences and how the new Web3 dApps differ from traditional internet apps.

## Internet Apps = Pay With Your Data

The implicit contract that internet apps have with its users is that they provide app services in exchange for access to your private data. Consider how many entities have access to your private data when you access a traditional web app.

* Your ISP is likely using your browsing habits to better monetize their ad targeting.
* The app itself has access to your private data while using the app.
* A whole range of tracking beacons are busy below the surface refining your user profile that's useful to advertisers by watching what you do on the app.

Since the collection of the data is free for the apps, they're economically incentivized to maximize the value of private user data as much as possible. This gives internet apps the power to potentially abuse private user data for profit. This includes the [ethically dubious practice](https://www.wsj.com/articles/t-mobile-hacker-who-stole-data-on-50-million-customers-their-security-is-awful-11629985105) of leaving customer data on minimally-secured servers in case it's valuable one day. We'll explore later how censorship is inextricable to both centralized server architectures and app companies collecting private user data.

## Web3: Users Have to Pay

In Web3, there's no free lunch in that every app action has a computing cost associated with it that needs to be paid by the user interacting with the app. In contrast to traditional internet apps, Web3 dApps:

* Use a crypto wallet to login. Your wallet address acts as your username in the Web3 ecosystem. Because many people aren't used to interacting with crypto wallets, this hurdle can make uptake among consumers more difficult for them.
* There's no longer private data being monetized to subsidize free apps as in web 2.0. Instead, users must pay the compute cost directly in crypto to use the app.

We couldn't say that this is a win in the Web3 column as logging in with a crypto wallet and having to pay for transactions yourself aren't great enticements to onboard new Web3 users. There are certainly usability benefits of internet apps that because of the current ease of use will never migrate over to Web3. Some users may not care that a trivial amount of their private data is being leaked back to a central corporation if they get a good benefit from an app. That's totally understandable, and each consumer has to make a cost-benefit analysis between privacy and the utility they get from free internet apps. In defense of Web3, crypto wallets are becoming easier to use. And even though Web3 users have to pay to use apps, the new paradigm opens up new avenues for users to [monetize their own private data](https://teaproject.medium.com/tea-project-allows-privacy-in-the-home-1ed42d6faac5).

## Internet Apps' Centralization = Censorship

A server-based internet app has multiple layers of centralization that might not be immediately evident. To see how these might negatively impact a typical internet app, let's imagine a modest social media app has just had an influencer publish a controversial post on their platform. The amount of attention the post gets begins to flood the app with new users who are actively publishing their agreement or disapproval of the influencer's message.

This triggers a few cascading events for this internet app that show the perils of centralization:

* **1. Bandwidth**: The newfound traffic exceeds the plan they've paid for and their connections are throttled and many requests are re-routed back to the originating server.
* **2. Infrastructure**: Their hosting provider doesn't know anything about the app's sudden virality and only see a huge spike in incoming connections. Afraid that all the traffic will negatively impact other customers on the same server, the host decides to take the social media app's website offline.
* **3. Application**: The app is happy with all the new traffic until their website is taken offline. They quickly realize that this new influencer is causing more trouble than they're worth and they decide to boot them off the platform.

The example above shows how any of the app's upstream infrastructure providers can pressue the app into censoring its users. And there's even more layers of centralization that can get an app disconnected from the internet:

* **4. Registrar**: Domain names can sometimes be taken offline by filing (even spurious) [DMCA copyright complaints](https://teaproject.medium.com/if-safe-harbor-is-dismantled-will-centralization-increase-7e6bf9327f68).
* **5. Security certificates**: Most often an app is adversely affected when they forget to renew their [SSL certificate](https://teaproject.medium.com/how-tea-projects-use-of-http-in-web3-is-more-secure-than-https-in-web-2-0-d488265af3d2).
* **6. DNS**: Over time, DNS providers like Cloudflare have become more interested in gatekeeping our ability to view internet content.

## Web3: Decentralized Through and Through

Everything mentioned in the above section about traditional internet app tech stack lists a whole roster of centralized infrastructure that's censorable. In contrast, Web3's core tenet of decentralization prevents any one player from taking an app down. By taking a look at the tech stack of a decentralized app and the infrastructure it runs on, we can quickly see the differences it has with internet cloud apps.

We'll use the TEA Project to show how Web3's infrastructure is decentralized throughout its tech stack. Instead of centralized server(s) hosting an internet app, the TEA network's miners host TApps based solely on their own hosting profitability. The bandwidth and compute power for a dApp (called a TApp in the TEA Project) will always be there as long as miners find it profitable enough to host the TApp.

Can user data be censored in a Web3 architecture like the TEA Project? Not from the hosting miners who don't know what's being run on their nodes. In the TEA Project, app code and user data stays encrypted in IPFS until they're decrypted within a miner's protected enclave for execution.

And TEA Project TApps don't require a domain name or even a traditional host for the front-end as the IPFS CID for the TApp is loaded from the nearest miner's IP address. TEA Project TApps also feature a [traditional 3-tier architecture](https://teaproject.medium.com/the-tapps-3-tier-decentralized-tech-stack-43d2872f609b) that makes app development straightforward. Additionally, all database queries are sent to distributed and decentralized nodes instead of a central database server.

Against the backdrop of centralized app stores, the TEA Project will have its own TApp store that will not censor any TApps from being offered there. Economic incentives ensure that miner nodes will only host TApps that are used by consumers and make the miner money.


# Magic of the State Machine

From a 10k foot view, all blockchains are nothing but different types of [state machines](/z_glossary/state_machine). This machine accepts a user tx as input, and then executes some kind of logic (for example, a smart contract) to update the [state](/z_glossary/state). Every block is a new update of the state. Any node can rebuild the latest state by recalculating from the genesis block. This recalculation is also part of the validation process.

TEA Proejct is also a state machine, but a very different type of state machine. There's no block, there's no TPS, no smart contracts, nand no validators. It's actually more likely a distributed database.

The smart contract is like the stored procedure in regular databases, but it's called the [state\_machine\_actor](/z_glossary/state_machine_actor) in the TEA Project. It can do more than just the basic operations that smart contracts can do, and it's much faster because there are no block limitations. That means the state updates are continously updating the local state separately without stopping every few seconds waiting for consensus. There's also no block size limitations, beause there's no block at all.

To achieve this, the most important thing is the sequence of all transactions (sometimes called events) that have to be identical among all [state machine replicas](/z_glossary/state_machine_replica). No one gets more or less transactions, no one gets them in a different order. Otherwise, the state would no longer be synced among all nodes.

The sequence of the transactions are guaranteed by the [conveyor](/z_glossary/conveyor). The algorithm is also called **proof of time**.

This unique way of thinking makes TEA Project a unique platform. Of course, this is based on the trust from layer1 and [remote attestation](/z_glossary/remote_attestation). Otherwise, any [hosting CML](/z_glossary/hosting_cml) nodes can cheat the [state machine replica](/z_glossary/state_machine_replica) with wrong [gps](/z_glossary/gps) timestamps and causes the whole system to stop working.


# Step by Step Tutorial

The tutorial section is designed to walk you through creating a TEA Project TApp that run as decentralized full compute-capable dApps. Developing a TApp is very similar to developing a typical web2 application. Even though TApps are "web3, you don't need to learn smart contracts or understand distributed systems. But there are still many differences with web2 apps and this tutorial is here to help you overcome these challenges. For more information on what skills are required to complete this tutorial as well as the proficiency required to be a TApp developer, read more in [dev prerequisites](/basic-concepts/010_developer_requirements).

During this tutorial, we'll build a simple TApplication step by step by cloning from a boilerplate repo called **tutorial-v1** and testing locally using the **dev-runner** repo. The app you'll build looks just like a typical "todo list" example you might've seen elsewhere in various web framework tutorials but we have a bit of an improvement. The worker who completes a task will get paid by the owner who created the task.

![Pasted image 20230319210108.png](/files/N1NK2IdpsWsryCJvXwva)

The tutorial is sectioned into multiple parts that build upon each other.

* The [setup section](/020_tutorial/010_install-dev-env) goes over the software that needs to be installed in your development environment.
* From there you can get started on a simple ["hello world" app](/020_tutorial/020_hello_world/021_local_build_and_unit_test) and get the UI to [display hello world](/020_tutorial/020_hello_world/022_dev-runner_the_local_development-environment).
* Next up is the [deploy section](/020_tutorial/030_deploy_helloworld_testnet) that shows you how to register your TApp as a real app running on the TEA network and uploading it to IPFS.

In the next section we actually start working on the actual todo list TApp.

* First up we learn how to implement [login with Metamask](/020_tutorial/040_add_login_feature) feature for our TApp where the user identity is tied to an Ethereum address. This section also introduces the faucet which endusers can use to get initial funds.
* Our TApp will need to store task data so we'll need to [initialize an SQL database](/020_tutorial/050_sql_crdt) in this step of the tutorial. The TEA Project offers an SQL database that's available to all TApps in the ecosystem.
* Next up is implementing [fund transfer](/020_tutorial/060_reward_fund_transfer) in our app so task workers can get paid for their work.
* And finally we [add gas payments](/020_tutorial/070_gas_fee_payment) into our simulated platform to make it as close as possible to the TEA Project mainnet. In web3, those that provide the compute infrastructure are compensated with gas payments. This step creates new log page which includes the gas payment log.

After following the full tutorial, you can read a [summary of what we've accomplished](/020_tutorial/080_summary). You shoulnd now be able to create your own TApps by adding your own business logic to the boilerplate.


# Install Dev Environment

## Install prerequisites

To install the dev environment in your local machine, you'll need some prerequisite software already installed:

* Git
* Docker: install docker and "docker compose". Note that we've only tested using the current version of Docker (20.10.23) and we suggest keeping your Docker updated to the latest version.
* Rust
* Node.js

Note that you'll need to use node version 14.14.0 for this tutorial. Make sure you have nvm 14.14.0 installed and set as default:

```
nvm install 14.14.0
nvm use 14.14.0
```

You can check which version of node is active using `nvm current`.

If you haven't installed wasm32-unknown-unknown target or the nightly version, you might be prompted to `rustup` and install them according to the instructions.

* `rustup target add wasm32-unknown-unknown`
* `rustup install nightly`

One of the build scripts that are used in the following tutorials might prompt that `protoc` couldn't be found. You can [follow the instructions to install it](https://grpc.io/docs/protoc-installation/#install-using-a-package-manager):

* **On a Mac**: `brew install protobuf`
* **On Ubuntu**: `apt install -y protobuf-compiler`

## Install local development environment: Dev-Runner

The purpose of the `dev-runner` repo is to allow any user to recreate the TEA runtime on their local machine. The TEA Project is a decentralized system that needs multiple nodes for both its hosting infrastructure and [state machine](/z_glossary/state_machine) where a [remote attestation](/z_glossary/remote_attestation) process ensures that all nodes are trustable. In the simplified local runtime, there's only one [hosting node](/z_glossary/hosting_cml) ("B-node") and one state machine node ("A-node"). And there's no remote attestation since this is a simulated environment with a single node on each level.

To install `dev-runner` to your local environment, use the following command:

`git clone https://github.com/tearust/dev-runner.git`

After you've dowloaded the `dev-runner` to your local computer, note that other repos will possibly interact with your local **dev-runner** environment as a sibling folder. For example, `tutorial-v1` will write a wasm file to `dev-runner` during the build process for that tutorial.

## Troubleshooting the Dev Environment

The most common cause of errors during the following tutorials generally either arise from an improperly configured local environment or from not having the most up to date repo.

* Misconfigured local environments can be fixed by following the error messages requesting missing packages. The prerequisites at the top of this document should be sufficient but everyone's local development environment will be unique.
* `git pull` your current tutorial's repo to make sure you have the latest files.

If you either change your local software environment or update your local repos, you'll need to stop any existing TEA runtime docker images. These are the steps for refreshing the `dev-runner` repo and associated docker images:

* Press `CTRL-C` to stop **dev-runner**.
* `docker compose down` (or `docker-compose down`) to stop the docker containers.
* Delete the `.tokenstate` using `rm -rf .tokenstate` to clear the stored state. This directory contains the local state's persistent storage in local dev mode. If you don't delete it, the next time you start the dev-runner will continue from the last saved [state](/z_glossary/state) . This may cause conflicts if you've updated your code logic.
* If there are any updates of the dev-runner docker images, use `docker pull the_images_of_the_two_:dev_image` to update the existing older images if there's an updated image available:

```
docker pull tearust/parent-instance-client:dev
docker pull tearust/runtime:dev
```

* After you've built the tutorials using your latest updates you'd run `docker-compose up` from the `dev-runner` directory.


# Hello World

<https://github.com/tearust/tutorial-v1> is the github repo of our tutorial. It can also be used as the boilerplate if you want to build a new TApp but don't want to start from scratch.

This repo has many branches with very branch a step in our tutorial. You can find the description for every branch in its associated README file.

The `master` branch and `login` branch are the most commonly used boilerplates. The `master` branch is a "hello world" example, and the `login` branch has almost all of the common basic features built-in.

If you want to verify that your development envionment is setup correctly, you can use the `master` branch and test the hello world. But if you're going to make a full featured TApp, the `login` branch might be a better choice because it comes with the basic TApp features, such as "login/out", "transfer funds", and "query balance". We believe most TApps would use those features, so we put them together into the utility library that comes with this `login` branch.

## Clone the tutorial master branch

Run `git clone https://github.com/tearust/tutorial-v1.git` to clone code to local.

If you'd like to check in your modified code to your own git repo, please rename the project to avoid conflict.

## Frontend and backend

There are two folders in the root of the **tutorial-v1** code repo:

* sample-actor: This is the back end lambda function that's similar to the backend web services in the web2 world.
* sample-front-end: This is the front end code that's similar to the frontend SPA in the web2 world.

In the future steps (branches) you'll see a new folder called sample-txn-executor. That's the transaction handler function that runs inside the [state machine](/z_glossary/state_machine). It's similar to the stored procedures of databases in the web2 world.


# Step 1: Build sample-actor and Run Unit Test

## Build sample-actor

The output of the build process is a Webassembly binary called `sample-actor.wasm`. This binary executable code will be loaded into the [TEA-runtime](/z_glossary/mini-runtime) which we'll talk about more in future steps. Now let's focus on how to build it.

Please make sure you've cloned the code and installed all dependencies as instructed in the previous step. In particular, make sure the following items have been installed correctly:

* rust nightly
* wasm32-unknown-unknown target
* protobuf

Now `cd sample-actor` and run `./build.sh` to build the actor.

Once built successfully, you can find the wasm file `sample_actor.wasm` in the `sample-actor/target/wasm32-unknown-unknown/release` folder. Note that in this step of the tutorial, we won't deploy to the TEA Project testnet, nor run in local single node development environment. We'll describe them more in later steps. In this initial step, we'll only run the unit test.

The **build.sh** script will also try to copy the **sample-actor.wasm** file to the `~/local/b-node` folder of the `dev-runner` repo. You'll get an error because you don't have that folder yet, but you'll create that folder in the next step of "running local development environment" tutorial.

If you get another error message, it's most likely due to some missing pieces in your development environment. Please go back and check for missing steps.

## Run sample-actor unit test

In this step, we won't run the sample-actor in your local development environment (called dev-runner). Instead, we'll just run a unit test.

You can run `cargo test` to run all the unit tests. You should see the test results as follows:

```
cargo test

running 3 tests
test tests::greeting_test ... ok
test tests::greeting_empty_string_should_err ... ok
test tests::add_test ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests src/lib.rs (target/debug/deps/sample_actor_codec-0cfabb9e4ae1c025)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests sample-actor-codec

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

```

When you want to test a request handler and expect it to return an error, you can use the following example:

```

#[tokio::test]
async fn greeting_empty_string_should_err() -> Result<()> {
  async {
    init().await?;
    let result = ActorId::Static(NAME).call(
      GreetingsRequest("".to_string()),
    )
    .await;

    assert!(result.is_err());
    Ok(())
  }
  .with_actor_host()
  .await
}

```

You should see that the tests have passed.

We highly recommend to write and run a unit test whenever you add / modify code. Building and deploying onto the testnet usually will take much longer than simply running a local unit test.

## Run sample-front-end

First from the root of the code repo, `cd sample-front-end`. If your backend has a different IP or port number other than the default localhost:8000, please edit the `.env.test` file to edit in your customized values:

```
VUE_APP_LAYER2_URL=http://127.0.0.1:8000
```

This address will be your backend service address.

Run the following to install dependencies: `npm install`

Then start the frontend local web server by running: `npm start`

If you can see the following:

```
  App running at:
  - Local:   http://localhost:3200/
  - Network: http://192.168.1.10:3200/

  Note that the development build is not optimized.
  To create a production build, run npm run build.
```

then your frontend is up and running.

At this moment, you cannot send requests to the backend and get a "hello world" message yet. We'll get into the local development environment in the next step.

You can send `Ctrl + C` to stop the frontend now.


# Step 2: Start the Local Dev Environment

## Unit test ->Dev runner ->Test net -> Production

TApp development needs 4 basic steps.

* Unit test: Run `cargo test` after every code change. This is the fastest way to test the logic.
* Dev runner: The local development environment. It's a simulator of the TEA Project runtime but running locally. Like Hardhat for Ethereum, this is the quickest way to test and verify the front end and back end logic integration.
* Testnet: This is **almost** the same as the final production environment but all the assets are not real so any mistakes won't cause real fund losses.
* Production: This is the last step where code is run in the real production environment. Please note that any mistake in your code may cause **real** fund losses.

In the previous step, we walked through the unit test. In this step, we'll walk through the Local Development Environment, called "Dev Runner".

The local development environment (dev-runner) is a docker configuration. It simulates one hosting node and one state machine node that runs in your local computer under docker. There's no hardware protection, so all Remote Attestation and consensus are simulated.

## Prerequisites for Installation

* Git
* Docker: install docker (version 20.10.23 or above) and "docker compose"
* Node.js. Again, make sure you're using node version 14.14.0.

## Running the tests

### Prepare your custom actors

If you have any custom wasm [actors](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/020_tutorial/020_hello_world/z_glossary/actor.md) that need to be loaded, you should place them in the directory `local`. In our sample-actor case, you can find the file located in the `tutorial-v1` repo at `~/sample-actor/target/wasm32-unknown-unknown/release/sample_actor.wasm`. Note that this file will be copied to the `local/b-node` folder of the `dev-runner` repo as part of the build process, and the **dev-runner** will load all wasm actors inside the `local` folder.

Let's build the **sample\_actor.wasm** file and copy it into the `dev-runner` repo. From the `tutorial-v1` repo, run `./build.sh` in the `sample-actor` folder to build the wasm file. In the last step of the build file it will copy it to the `local/b-node` directory of `dev-runner`.

### Start the docker container servers

You can run with server mode by doing the following:

```
docker compose up
```

(If you installed `docker-compose` please replace the `docker compose up` command with `docker-compose up`)

Please wait for all the containers to start and confirm that the log isn't showing any errors.

### Use CURL to send json http post request without front end

While the server's running, open another terminal and run the following:

```
curl -H "Content-Type: application/json" -d '{"actor": "someone.sample", "address": "0x0000000000000000000000000000000000000000"}' http://localhost:8000/say-hello
```

You should see the following output:

```
"Hello world!"
```

Now you know the server is running and the sample actor responds as expected.

You can also use Postman or any testing tools to simulate a front end sending requests to the server. Just make sure:

* Use the following address: `localhost:8000/say-hello`
* json request
* http post
* Use the json request as given above

In our next session we'll create a sample-front-end project. It will run such requests in the browser to make future tutorials easier.

### Start the front end

Make sure you're in the `sample-front-end` folder of the `tutorial-v1` repo and to start the front-end run the following commands:

```
npm install
npm start
```

Open a browser and visit \[[http://127.0.0.1:3200](http://127.0.0.1:3200/)].

You should see a page with the text "Welcome to Sample Actor testing page" and a single button, "click here to send request".

![Screenshot 2023-04-28 at 2 27 33 PM](https://user-images.githubusercontent.com/86096370/235257641-28880e62-5542-4582-99da-a3705bec0647.png)

Clicking on the button should result in a "Hello world!" popup.

Please make sure your dev-runner is up and running. If not, follow the instructions in the previous steps. If the backend is running correctly, you can click the button to send a request to the sample-actor. You should see the response in a browser alert:

```
{"data":"Hello world!","status":200,"statusText":"OK","headers":{"content-length":"14","content-type":"application/json"},"config":{"url":"/say-hello","method":"post","data":"{\"actor\":\"someone.sample\",\"address\":\"0x000000000000000000000000000000000000000f\"}","headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json;charset=utf-8"},"baseURL":"http://127.0.0.1:8000","transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1},"request":{}}
```

Congratulations! Your first TApp is correctly running in your local development environment.

In the next step, you'll learn how to deploy it to the testnet.

## Limitations of dev-runner

Dev-runner is a docker simulation of the real TEA-runtime. It's different in the following aspects:

* There's no hardware security.
* There's only one host node and one state machine node.
* No consensus is required since there's only one state machine node.
* There's no real remote attestation. All nodes are assumed to be "good " nodes.
* There's no layer-1 (Ethereum) interaction.
* All initial funding is provided in the DAO\_RESERVE account. Of course, this money is fake.

You can stop the docker container at any time, and it will get back to the original state when you restart . You cannot store the state.


# Sample Actor Code Walkthrough

Assuming you've successfully built and run the unit test, let's get into the code structure details of this sample [actor](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/020_tutorial/z_glossary/actor.md).

### Folder structure overview

```
ls
Cargo.lock          README.md           codec               rust-toolchain.toml
Cargo.toml          build.sh            impl                target
```

Folders and their usage:

* `Cargo.lock` is a temp file generated during building. It doesn't require further inspection unless you want to check the dependency versions.
* `Cargo.toml` is the root cargo config of this project. It contains only two other workspaces: `codec` and `impl`.
* `build.sh` is the script that builds the wasm [actor](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/020_tutorial/020_hello_world/z_glossary/actor.md).
* `codec` is one of the two main workspaces. It's related to the definitions of the data structures that will be used by other modules. Consider it an "interface" definition.
* `impl` is another of the two main workspaces. It's related to the implementation of the code logic.
* `rust-toolchain.toml` defines the build environment, versions. etc
* `target` is generated during build process. It stores the compiled wasm actor and temp files.

Most of the time, you only need to work on the codec and impl folders without touching any of the other files/folders.

The `Cargo.toml` file:

```
cat Cargo.toml
[workspace]
members = ["codec", "impl"]
resolver = "2"

[workspace.dependencies]
tea-sdk = {git="https://github.com/tearust/sdk", branch="master"}
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.94"
log = "0.4.17"
thiserror = "1.0.39"
tokio = "1.26.0"
```

The `rust-toolchain.toml` file:

```
cat rust-toolchain.toml
[toolchain]
channel = "nightly-2023-01-01"
components = ["rustfmt", "clippy"]
```

The `build.sh` file:

```
cat build.sh
#!/bin/bash

cd $(dirname $0)
cd impl

cargo build --target wasm32-unknown-unknown --release

if [ $? -ne 0 ]; then
  exit 1
fi


if ! command -v tas &> /dev/null
then
    cargo install tea-actorx-signer --version 0.2.0-dev.5
fi

tas ../target/wasm32-unknown-unknown/release/sample_actor.wasm
echo "copy to dev-runner"
cd ..
cp -r target/wasm32-u

```

### codec folder

Use `ls` to list the files in the `codec` folder:

```
Cargo.toml src
```

The contents of the `Cargo.toml` file inside the codec folder:

```
[package]
name = "sample-actor-codec"
version = "0.1.0"
edition = "2021"

[dependencies]
tea-sdk = { workspace = true }
serde = { workspace = true }
```

In the package section, you can modify your project name, version etc.

There are two dependencies:

* tea-sdk is the main sdk entry to all other TEA sdk modules.
* serde is [crates.io/crates/serde](https://crates.io/crates/serde).

In our tutorial, while adding more logic to the project, we'll have more and more dependencies added into this Cargo file.

Use `ls` to list the files in the src folder:

```
error.rs lib.rs
```

Let's take a look into `error.rs` using `cat error.rs`:

```
use tea_sdk::{actorx::error::ActorX, define_scope};

define_scope! {
    SampleActor: ActorX {
        HttpActionNotSupported;
        GreetingNameEmpty;
    }
}
```

Rust is a strong typed language which requires all error types to be defined in detail. In the code above we've defined two error types that are used in our sample-actor.

* **HttpActionNotSupported**: In this version of the code, only http GET is handled while other types may throw this error.
* **GreetingNameEmpty**: When receiving a Greeting request from the client, the logic requires a name field inside the request. This name will be used in the response string such as "Hello your-name". But if the name field is empty, the handler will throw this error.

When new errors need to be created, simply add new Error names under the `define_scrope!` macro. We'll see more examples like this in the later steps of this tutorial.

Let's take a look into `lib.rs` using `cat lib.rs`:

```
#![feature(min_specialization)]

use serde::{Deserialize, Serialize};
use tea_sdk::serde::TypeId;

pub mod error;

pub const NAME: &[u8] = b"someone.sample";

#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
#[response(())]
pub struct GreetingsRequest(pub String);

#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
pub struct AddRequest(pub i32, pub i32);

#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
pub struct AddResponse(pub i32);
```

In this file we defined three structure types:

* **GreetingRequest**: This request needs a parameter String. It could be a developer's name like Alice.
* **AddRequest**: This is another example handler that adds two i32 numbers from the input.
* **AddResponse**: Send back the result of adding two input numbers.

There is no **GreetingResponse** because we just print the "Hello Alice" to the console without any return to the client for demo purposes. In order to make the compiler happy, you would need to have the `#[response(())]` line. This tells the compiler that this request doesn't attach a response type written by the developer, but it does return a () as response. If you don't have such a line, the compile will give you an error because it considers that you missed a response.

Request and Response are the most important concepts in the actor design, it deserve a standalone chapter to explain. Please go to the ["understand request and response" chapter](/020_tutorial/020_hello_world/025_understand_request_and_response) in this tutorial step to learn more.

There's another HTTP GET handler to deal with client request that returns "Hello World". We'll get into that when we walk through the `impl` workspace.

### impl folder

Let's `cd impl` and `ls`:

```
Cargo.toml    key.pem       manifest.yaml src
```

Let's look at the `Cargo.toml` file with `cat Cargo.toml`:

```
[package]
name = "sample-actor"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
sample-actor-codec = { path = "../codec" }
tea-sdk = { workspace = true, features = ["wasm"] }
thiserror = { workspace = true }
serde_json = { workspace = true }
log = { workspace = true }

[dev-dependencies]
tea-sdk = { workspace = true, features = ["host"]}
tokio = { workspace = true, features = ["full"] }
```

Note the line `sample-actor-codec = { path = "../codec" }`.

We'll need to use the data types defined in the codec folder.

**key.pem** is a private key file that the developer of this actor knows. It's used for verification purposes by the [TEA-runtime](/z_glossary/mini-runtime) to check if the final built wasm binary is correctly signed by the original developer when upgrading. You can generate key.pem using the openssl tool: `openssl genrsa -out key.pem`. As a developer, please make sure you keep the key.pem file securely stored. Whoever has such a pem file can impersonate you to sign a malicious wasm file under your name.

Let's look at the `manifest.yaml` file with `cat manifest.yaml`:

```
actor_id: sample
owner_id: someone
token_id: 0000000000000000000000000000000000000000
access:
  - tea:adapter
```

The **manifest** is an important definition file for this actor. It's part of the binary wasm that's signed during the build.

The **actor\_id** should be a unique id for every actor. An example of a typical actor name is "com.tea\_core\_team.sample\_for\_tutorial". We'll release a naming convention later.

The **owner\_id** is the developer's ETH address (H160). Make sure you input it correctly as it's used for payment.

The **token\_id** is the H160 ETH address that the TApp owns. Before deployment, the developer needs to create such a TApp in the TEA developer portal first to obtain a token\_id for this TApp. In our local dev-runner, it's ok to set it to 0x0, since we won't be using the Developer Portal in the local dev-runner. All actors that work for this TApp will need to use this token\_id for billing purposes. It's important to match the owner of the TApp, the owner\_id, to your ETH address as the developer. The Developer Portal will reject your request if there's a mismatch during deployment or upgrade.

The `access` is a public disclaimer that lists of all the other modules that this actor will communicate with. Please make sure you only claim the modules that this actor absolutely needs to communicate with, otherwise it may cause security concerns from users. For example, if an actor claims to communicate a billing related module that it's not permitted to access, the end user or reviewers would mark this as a security concern for this actor in the community. On the other hand, if this actor attempts to communicate with another module that's not listed in the `access` list, it will be rejected at runtime by the TEA security logic.

If you `cd` into the `src` folder, you can run `ls` to see the three files:

```
error.rs lib.rs   tests.rs
```

* `error.rs` defines the Error typess
* `lib.rs` is the main entrance point for the code logic.
* `tests.rs` contains all unit tests.

Using `cat error.rs` to view the `error.rs` file:

```
use sample_actor_codec::error::SampleActor;
use tea_sdk::define_scope;
use thiserror::Error;

define_scope! {
    Impl: SampleActor {
        HttpActionNotSupported => @SampleActor::HttpActionNotSupported;
        HttpActionNotSupported => @SampleActor::GreetingNameEmpty;
    }
}

#[derive(Debug, Error)]
#[error("Http method {0} is not supported")]
pub struct HttpActionNotSupported(pub String);

#[derive(Debug, Error)]
#[error("Greeting name is empty")]
pub struct GreetingNameEmpty;
```

Remember that we've defined `HttpActionNotSupported` and `HttpActionNotSupported` IDs in the codec project. Here we'll put them into `SampleActor` to connect those IDs to the actually structures defined right below.

Let's use the `HttpActionNotSupported` as an example:

```
#[derive(Debug, Error)]
#[error("Http method {0} is not supported")]
pub struct HttpActionNotSupported(pub String);
```

This error has a parameter string. When it throws this error, the name of the unsupported method can be assigned as the parameter, so that the user can get a more meaningful error detail. The error string will look like "Http method POST is not supported" in case of "post".

The `lib.rs` file has all the main logic that handles requests:

```
cat lib.rs
#![feature(min_specialization)]
#![allow(incomplete_features)]
#![feature(async_fn_in_trait)]

use crate::error::GreetingNameEmpty;
use error::{HttpActionNotSupported, Result};
use sample_actor_codec::{AddRequest, AddResponse, GreetingsRequest, NAME};
use tea_sdk::{
    actors::adapter::HttpRequest,
    actorx::hooks::{Activate},
    actorx::{actor, ActorId, HandlerActor},
    serde::handle::{Handle, Handles},
    utils::wasm_actor::logging::set_logging,
    Handle, ResultExt,
};

#[cfg(not(test))]
use ::{log::info, tea_sdk::utils::wasm_actor::actors::adapter::register_adapter_http_dispatcher};

pub mod error;
#[cfg(test)]
mod tests;

actor!(Actor);

#[derive(Default, Clone)]
pub struct Actor;

impl Handles for Actor {
    type List = Handle![
        Activate,
        HttpRequest,
        GreetingsRequest,
        AddRequest
    ];
}

impl HandlerActor for Actor {
	fn id(&self) -> Option<ActorId> {
		Some(NAME.into())
	}

	async fn pre_handle<'a>(&'a self, req: &'a [u8]) -> Result<std::borrow::Cow<'a, [u8]>> {
		set_logging(false, false);
		Ok(std::borrow::Cow::Borrowed(req))
	}
}

impl Handle<Activate> for Actor {
    async fn handle(&self, _: Activate) -> Result<()> {
        #[cfg(not(test))]
        {
            register_adapter_http_dispatcher(vec!["say-hello".to_string()]).await?;
            info!("activate sample actor successfully");
        }
        Ok(())
    }
}


impl Handle<HttpRequest> for Actor {
    async fn handle(&self, HttpRequest { action, .. }: HttpRequest) -> Result<Vec<u8>> {
        log::info!("@@ aa => {:?}", action);
        match action.as_str() {
            "say-hello" => serde_json::to_vec("Hello world!").err_into(),
            _ => Err(HttpActionNotSupported(action).into()),
        }
    }
}

impl Handle<GreetingsRequest> for Actor {
    async fn handle(&self, GreetingsRequest(name): GreetingsRequest) -> Result<()> {
        if name.is_empty() {
            return Err(GreetingNameEmpty.into());
        }

        println!("Hello, {name}!");
        Ok(())
    }
}

impl Handle<AddRequest> for Actor {
    async fn handle(&self, AddRequest(lhs, rhs): AddRequest) -> Result<AddResponse> {
        Ok(AddResponse(lhs + rhs))
    }
}

```

You can leave those macros untouched by your project. Those macros are designed to simplify the code.

First we define the actor structure:

```
#[derive(Default, Clone)]
pub struct Actor;
```

Then we list all Types that should be handled using:

```
impl Handles for Actor {
    type List = Handle![
        Activate,
        HttpRequest,
        GreetingsRequest,
        AddRequest
    ];
}
```

After this we implement those trait Handles by writing `impl HandlerActor for Actor` and fill in the code logic for each impl.

In our sample actor example, we only handle three developer-defined instances of business logic and one system request which is called `Activate`.

Activate is called when the actor is loaded into the runtime for the first time and starts running. The default behavior is in the following code:

```
impl Handle<Activate> for Actor {
    async fn handle(&self, _: Activate) -> Result<()> {
        #[cfg(not(test))]
        {
            register_adapter_http_dispatcher(vec!["say-hello".to_string()]).await?;
            info!("activate sample actor successfully");
        }
        Ok(())
    }
}
```

These code register this actor to the http adapter because this actor will need to receive http requests from the outside world. Once registered, the http adapter (another service running outside of the enclave) will know where to dispatch the http request.

In our case, we add a `say-hello` string vec as the **action name**. This action name will be used when handling http requests later. Beause our sample actor is so simple it doesn't have any complex logic. We simply put a "say-hello" whenever we receive an http request regardless what the request content is. We'll see more complicated examples in the future steps of our tutorial.

Here we handle the HttpRequest:

```
impl Handle<HttpRequest> for Actor {
    async fn handle(&self, HttpRequest { action, .. }: HttpRequest) -> Result<Vec<u8>> {
        log::info!("@@ aa => {:?}", action);
        match action.as_str() {
            "say-hello" => serde_json::to_vec("Hello world!").err_into(),
            _ => Err(HttpActionNotSupported(action).into()),
        }
    }
}
```

Because we registered the http request to the "say-hello" action name, it should always get a 'Hello world!' string.

To demonstrate a more complex case, let's imagine the request contains a parameter (the developers name). For that we have the GreetingsRequest:

```
impl Handle<GreetingsRequest> for Actor {
    async fn handle(&self, GreetingsRequest(name): GreetingsRequest) -> Result<()> {
        if name.is_empty() {
            return Err(GreetingNameEmpty.into());
        }

        println!("Hello, {name}!");
        Ok(())
    }
}
```

In this example handler, the `name` is the parameter of the request. The handler checks if it's empty then returns a GreetingNameEmpty error. If it's not empty, then print the `Hello, THE_INPUT_NAME !` to the console. That's why you can see it when you run the unit test.

We can also have have multiple parameters in one request. We have the AddRequest handler to demonstrate this:

```
impl Handle<AddRequest> for Actor {
    async fn handle(&self, AddRequest(lhs, rhs): AddRequest) -> Result<AddResponse> {
        Ok(AddResponse(lhs + rhs))
    }
}

```

This handler simply adds up two input numbers and returns the sum.

Note, the GreetingRequest and AddRequest don't have http registered, so you cannot call them directly from the browser by sending an http request. They're only available for unit testing in our current step. We'll add more http request handlers in the future steps of this tutorial.

You can find how those requests are handled and what the expected results are from the `test.rs` source code.

Writing unit tests is very important for TEA development.

Here's an example unit test file, `test.rs`:

```
use sample_actor_codec::{AddRequest, AddResponse, GreetingsRequest, NAME};

use crate::{Actor, error::Result};
use tea_sdk::actorx::{ActorExt, WithActorHost, ActorId};

async fn init() -> Result<()> {
	Actor::default().register().await?;
	Ok(())
}

#[tokio::test]
async fn greeting_test() -> Result<()> {
  async {
		init().await?;
		ActorId::Static(NAME).call(
      GreetingsRequest("Alice".to_string()),
    )
    .await?;
    Ok(())
	}
	.with_actor_host()
	.await
}

#[tokio::test]
async fn greeting_empty_string_should_err() -> Result<()> {
  async {
    init().await?;
    let result = ActorId::Static(NAME).call(
      GreetingsRequest("".to_string()),
    )
    .await;

    assert!(result.is_err());
    Ok(())
  }
  .with_actor_host()
  .await
}

#[tokio::test]
async fn add_test() -> Result<()> {
  async {
    init().await?;
    let AddResponse(result) = ActorId::Static(NAME).call(AddRequest(1, 2)).await?;
    assert_eq!(result, 3);
    Ok(())
  }
  .with_actor_host()
  .await
}
```


# Sample Front-end Code Walkthrough

The `master` branch of the tutorial is just a simple "hello world" example. There's not much front-end logic to explain. In contrast, the `login` branch is a **typical** TApp boilerplate. We'll dig into more detail on the `login` branch when we get there in our next step.

For the current `master` branch, you can see a typical VUE front-end Single Page Application.

> Note: You can use any front end framework to build your own front end. TEA Project is not a front end framework, it works with any type of front end framework. We use VUE as an easy example.

The only hello world related code is in `Home.vue`

This is the code:

```
import {_, axios} from 'tearust_utils';
export default {
  data(){
    return {};
  },
  methods: {
    get_env(key) {
      const x_key = 'VUE_APP_' + _.toUpper(key);
      return _.get(process.env, x_key, null);
    },
    async send_request(){
      const _axios = axios.create({
        baseURL: this.get_env('LAYER2_URL'),
      });
      const rs = await _axios.post('/say-hello', {
        actor: 'someone.sample',
        address: '0x000000000000000000000000000000000000000f'
      });
      alert(rs.data);
    }
  }
};
```

It simply sends an axios post to `/say-hello` with the following JSON content:

```
{
    actor: 'someone.sample',
    address: '0x000000000000000000000000000000000000000f'
}
```

This is an example of how we test the sample-actor using CURL or Postman.

Another thing we need to mention is the LAYER2\_URL env var. This is the address to the [backend actor](/z_glossary/back_end_actor). It's defined in the `.env.test` file. During you local testing, by default it is set to your local IP address port 8000.

```
NODE_ENV = dev
VUE_APP_LAYER2_URL=http://127.0.0.1:8000
```

If you have a special environment settings that the backend is not running on 127.0.0.1:8000, please make sure you change this value.


# 025\_understand\_request\_and\_response

### The basic and advanced topics in this article

You don't need to understand all the contents in this article. Most are advanced topics that are only for those advanced readers. It's totally fine to skip this article and continue this tutorial as long as you understand the following items:

* The request and response are all what the actors do.
* Copy and paste the type definition from the boilerplate and add your own types following the same template. Pay attention to the parameter types.
* In most cases, it should work just fine. If not, please come back to read the advanced topics below. Good luck!

### What does derive(TypeId) mean?

In our hello\_world tutorial, you've seen the Requests and Responses defined in the codec/src/lib.rs like this:

```
#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
#[response(())]
pub struct GreetingsRequest(pub String);

#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
pub struct AddRequest(pub i32, pub i32);

#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
pub struct AddResponse(pub i32);
```

Even if you're a rust veteran, you may still want to ask what does the TypeId mean or response(()) mean?

A type with `TypeId` derive means it can be sent throw actor calls. It's always ok to be used a a response but it still needs a response type to be used as a request since a request should have a response type.

Note that a response of the unit type `()` is logically the same as what it means in rust's type system. `()` means the value exists, but without any state provided, as opposed to the never typed `!`, which means it didn't ever exist. If some operation results in `Ok(())`, it at least means the operation is completed successfully.

A request must have a response, and a `#[response(())]` enables it to be used as a request that returns a `()` as a response. By default, a type with `TypeId` derive does not attach a response type, which means it cannot be used as a request unless an explicit `#[response(SomeResponseType)]` is provided. But as for types named with a `Request` suffix, it means it must be a request type and should have a response type, it automatically attaches a response type definition to the same name with the `Request` suffix replaced by `Response`. A macro cannot check whether a type with some name exists, therefore this response type being missing would be a compiling error.

As for types named with a `Request` suffix but also with a `#[response(SomeResponseType)]`, the default behavior is overridden since the explicit attribute always has the highest priority.

Eg:

```
#[derive(TypeId)]  
struct SomeNormalType; // No response type defined, so that it could only be used as a response

#[derive(TypeId)]  
#[response(())]  
struct SomeOtherNormalType; // This type could be used as a request with response of type `()`

#[derive(TypeId)]  
struct SomeRequest; // This binds `SomeResponse` as its response type. Note that our system searches for "Request" in struct under derive(TypeID) and if found will add a "Response" struct. Therefore if the developer declares: 

`#[derive(TypeId)]  
struct SomeRequest;`

the code is actually converted into:

#[derive(TypeId)]  
struct SomeRequest;
struct SomeResponse;

The last line was added automatically by the compiler.

#[derive(TypeId)]  
struct SomeResponse; // No response type defined, so it could only be used as a response. It's therefore a regular rust struct with no special treatment done to add a response.

Note that because "Request" isn't in the struct here, no additional conversion is generated, i.e. SomeResponse won't be split into two struct and just be left as is

#[derive(TypeId)]  
struct SomeOtherRequest; // This binds `SomeOtherResponse` as its response type, but `SomeOtherResponse` doesn't exist, so it becomes a compiling error.  
```

The serialized request and response types are identified by the type id as the head of the binary data, so these types have to implement the trait `TypeId`, which works different from rust's `std::any::TypeId`, whose generated identifier is only guaranteed to be unique within a compilation. But it's obviously insufficient for the types that are to be transmitted through processes and wasm instances that are loaded from different compilations.

Our workaround is to define the trait `TypeId` along with its derive macro, which is a pure function evaluated during the compile time. It's only input is the code of the type definition, as a token stream, lexed by the rust compiler. And the only output is an extra token stream in order to emit extra definitions (mainly to implement the trait with the same name as the macro) that are to be compiled along with the original type definition.

What a derive macro do is to parse the token stream into an abstract syntax tree (aka. AST), and analyze the AST to get all information in need to generate extra definitions, such as `impl` blocks. Note that input tokens come with its span information, including the package name, version, module path, filename, line & column number, and whether it is from the hand-written code or generated from a previous macro.

Note that derive macro, as a procedure macro, is evaluated right before the souce being parsed into an AST. While it's far before the typed high-level intermediate representation (aka. THIR) stage, that's where type information is generated. Thus a procedure macro (or anything else in rust code) doesn't have the ability to scan all types.

As for each type for which a `TypeId` derive is applied, the derive macro generates a definition that `impl`s  `TypeId for` such type, of which the only trait member is a const string that would be used as the unique id among compilations. The derive macro generates the type id by concating the package name with version, the module path, and the name of such type, which could guarantees that, for any crate that reference `tea-sdk` of a certain version, no matter how and where it's compiled, the type id is ensured to be certain and unique.

Additionally, rust allows extra attributes to be attached after the derive macro (aka. helper attributes) as extra arguments for the derive macros. The `TypeId` derive macro looks for `response` helper attributes to indicate whether and `for` what type the derive macro should generate `impl Request`, of which the only trait member is `type Response` that indicates the response type of such type (when used as a request).

The ideal design is to check whether a `Response` suffixed type exists for the `Request` suffixed type. Otherwise it uses `()` instead to automatically bind the response type without errors. But as explained above, a procedure macro is unable to access the type information. It can only access the literal code information of the type definition where the derive macro is attached, as token stream, so it infers the `Response` suffixed name as the response type regardless of whether it exists. Therefore a `#[response(())]` is needed to tell the macro to use `()` instead.

### Better example for Requests and Response definition

The tutorial is meant to be simple and clear. So we intend to have only a few examples of requests and responses. A better example for different types of request/response would be inside the sdk codebase. It is located inside the sdk code repo, under actorx/examples. The Github link is \` <https://github.com/tearust/sdk/blob/master/actorx/examples/codec/src/lib.rs>.

Here's the example code at the time of this document was written:

```
#![feature(min_specialization)]

use serde::{Deserialize, Serialize};
use tea_sdk::{actorx::ActorId, serde::TypeId};

pub const WASM_ID: ActorId = ActorId::Static(b"com.tea.examples-actor");
pub const NATIVE_ID: ActorId = ActorId::Static(b"com.tea.time-actor");

#[derive(Serialize, Deserialize, TypeId)]
#[response(())]
pub struct GreetingsRequest(pub String);

#[derive(Serialize, Deserialize, TypeId)]
pub struct AddRequest(pub u32, pub u32);

#[derive(Serialize, Deserialize, TypeId)]
pub struct AddResponse(pub u32);

#[derive(Serialize, Deserialize, TypeId)]
pub struct GetSystemTimeRequest;

#[derive(Serialize, Deserialize, TypeId)]
pub struct GetSystemTimeResponse(pub u128);

#[derive(Serialize, Deserialize, TypeId)]
pub struct FactorialRequest(pub u64);

#[derive(Serialize, Deserialize, TypeId)]
pub struct FactorialResponse(pub u64);
```

There might be some updates in the future.

In the actor/src/lib.rs you can find how they're implemented:

```
#![feature(min_specialization)]
#![feature(async_fn_in_trait)]
#![allow(incomplete_features)]

use crate::error::Result;
use tea_actorx_examples_codec::{
	AddRequest, AddResponse, FactorialRequest, FactorialResponse, GetSystemTimeRequest,
	GetSystemTimeResponse, GreetingsRequest, NATIVE_ID, WASM_ID,
};
use tea_sdk::{
	actorx::{actor, hooks::Activate, println, ActorId, HandlerActor},
	serde::handle::handles,
};

pub mod error;

actor!(Actor);

#[derive(Default)]
pub struct Actor;

impl HandlerActor for Actor {
	fn id(&self) -> Option<ActorId> {
		Some(WASM_ID)
	}
}

#[handles]
impl Actor {
	async fn handle(&self, _: Activate) -> Result<_> {
		println!("Activate!");
		Ok(())
	}

	async fn handle(&self, GreetingsRequest(name): _) -> Result<_> {
		let GetSystemTimeResponse(time) = NATIVE_ID.call(GetSystemTimeRequest).await?;
		println!("Hello {name}, the system time is {time}.");
		Ok(())
	}

	async fn handle(&self, AddRequest(lhs, rhs): _) -> Result<_> {
		Ok(AddResponse(lhs + rhs))
	}

	async fn handle(&self, FactorialRequest(arg): _) -> Result<_> {
		Ok(FactorialResponse(if arg <= 2 {
			arg
		} else {
			arg * WASM_ID.call(FactorialRequest(arg - 1)).await?.0
		}))
	}
}
```

You can find more examples from other projects.


# Deploy Hello World on Testnet

**NOTE: this section is currently under development. There's currently no DevPortal URL. When the link becomes available, we'll remove this notice when it's ready to be deployed**

In this section of the tutorial, we'll use the dev portal to deploy the **Hello World** boilerplate to the TEA testnet. The goal is to see the `Hello [developer's name]` TApp in the browser after launching such a TApp from the TAppStore.

## Prerequisites

Besides the prereqs stated earlier, this tutorial involves uploading to IPFS and will require [installing the IPFS command line tool](https://docs.ipfs.tech/install/command-line/#system-requirements). For those running MacOS it's also available through Homebrew:

`brew install ipfs`

You'll also need some TEA funds in your wallet to use the Developer Portal. You can request funds by sending us a message in our [Telegram group](https://t.me/teaprojectorg).

## Clone the tutorial master branch

Run `git clone https://github.com/tearust/tutorial-v1.git` to clone code to local. Recall that there are two folders in the root of the **tutorial-v1** code repo:

* sample-actor (the back end lambda function).
* sample-front-end (the front end code).

If you'd like to check in any of your modified code to your own git repo, please rename the project to avoid any conflicts.

## Setup TApp

* Login to the Devportal with Metamask: (link will be updated here when ready)
* You can see your account balance after login.
* Go to the TApps page in the Devportal. Here you'll create a new TApp and save the token\_id:

![Screenshot 2023-04-14 at 4 52 21 PM](https://user-images.githubusercontent.com/86096370/232627849-ca3a14cb-d3b5-4358-b022-ee86652d7187.png)

We will add this token\_id minus the leading `0x` to `~/sample-actor/impl/manifest.yaml` at line 3. You should also change the actor name from `sample-actor` to a unique name.

![image](https://user-images.githubusercontent.com/3214173/231840591-775730aa-1900-4c76-adb6-791f9dd2f467.png)

## Build and upload actor to IPFS

You can build your actor using the same commands we used in the previous step: `cd sample-actor` and run `./build.sh` to build the actor.

To upload the actor to IPFS, run `./ipfs.sh` from the same directory which executes the following script:

![image](https://user-images.githubusercontent.com/3214173/231841142-35201bb1-a818-4dc0-b754-d9fca8e04b51.png)

Save the CID returned from the script to use in the next step.

![image](https://user-images.githubusercontent.com/3214173/231841451-4587904d-7e11-4689-b1ae-f308dd6bacb6.png)

## Update TApp metadata in the Devportal

Go back to the Devportal and click the cog icon next to your TApp listing in the **Developer** tab.

![image](https://user-images.githubusercontent.com/3214173/231842662-30bf5a95-a2ec-47d0-93d1-b1b861bdb463.png)

Enter in the information as instructed in the following image to update your TApp's metadata:

![image](https://user-images.githubusercontent.com/3214173/231844198-11dceef7-c2d8-45a4-b636-9cc16b52d5c4.png)

If you get a **spend\_over\_allowance** error:

![Screenshot 2023-04-18 at 12 18 17 PM](https://user-images.githubusercontent.com/86096370/232887275-9d7cfb59-dd72-4537-a247-f0225c787b9b.png)

Then you'll need to increase the spending limit for the **Developer Portal** in the [Nitro TAppStore](http://54.180.82.194:8080/ipfs/QmS5K9u8rfWpAxgonJeB4pX1qMyBqpz9A8Etb2GuTFFhts/):

![Screenshot 2023-04-18 at 12 20 53 PM](https://user-images.githubusercontent.com/86096370/232887289-2a055984-dd9a-4ef5-a763-92d6d2966940.png)

Here you can set the spending limit up to the amount you have in your TEA wallet:

![Screenshot 2023-04-18 at 12 29 24 PM (2)](https://user-images.githubusercontent.com/86096370/232887293-16ba1b14-10b3-473c-b38c-f8170ee02630.png)

## Build and upload front-end

Build the front-end code (jacky\_test/sample-front-end/) and upload to IPFS using `~/sample-front-end/ipfs.sh`.

Upon succesful completion you'll save the CID of the front-end to use in the next section (the CID is on the last line ending with `dist`).

![image](https://user-images.githubusercontent.com/3214173/231847211-848c89f0-f0ec-4d2a-ae8e-0b908b8e34c3.png)

## Update the front-end CID in Devportal

Edit your TApp and enter in the CID for the front-end:

![image](https://user-images.githubusercontent.com/3214173/231859470-e13f5b74-a345-46d4-8172-529ac0e203d0.png)

* Visit front-end code in ipfs using the URL format `http://54.180.82.194:8080/ipfs/[CID]/#/welcome`

In our current example it would be `http://54.180.82.194:8080/ipfs/QmdGoyx5JLinEPM8ZiMNaXkVjbqmg2rWygvxPBWPNKou4A/#/welcome`

Note that the actor will be loaded after the first request. If you see an error "you need to try later", that means the node is loading the actor and will be available when you try later after it's been loaded.

## Activate the TApp in the Devportal

Activating the TApp will make it available on the TEA network. To activate your TApp, press the start button next to it in the Devportal:

![image](https://user-images.githubusercontent.com/3214173/231850827-97495908-f12d-44fe-b1d3-59078ec4778a.png)

Once it's active, other users can launch the TApp through [the TAppstore](http://54.180.82.194:8080/ipfs/QmS5K9u8rfWpAxgonJeB4pX1qMyBqpz9A8Etb2GuTFFhts/).

![image](https://user-images.githubusercontent.com/3214173/231851272-a56a99b0-a7ff-404d-be1a-1bf5c2d16bd8.png)


# Add Login Feature

## Features in this step

In this step, we'll add the following features in to the first "hello-world" boilerplate:

* Login using Metamask.
* Look up account balance.
* Use faucet to get some TEA tokens for testing.

These features are the most common features for almost every TApp (the faucet only works in the local development environment, not on testnet or production). You may want to use the `login` branch as the boilerplate instead of the `master` branch because he `master` branch only has the "hello-world" example.

## Switch to the login branch and test run

Run `git checkout login` to switch to the login branch.

Now you'll use what you've learned in previous steps to build and run the code on top of "dev-runner" and see how it works.

Build the [actor](/z_glossary/actor) in the `sample-actor` folder by running `./build.sh`.

Go to your local `dev-runner` folder and check that the `local/b-node/sample-actor.wasm` file is the most recent version.

```
total 9224
-rw-r--r--@ 1 kevinzhang  staff       85 Mar 10 12:29 README.md
-rwxr-xr-x@ 1 kevinzhang  staff  4118177 Mar 11 13:51 sample_actor.wasm
```

If the `sample_actor.wasm` file isn't recent, check if your build failed.

From the **dev-runner** repo root directory, run `docker compose up`. **Make sure you wait** about 2 minutes untill all actors are successfully activated.

In a different terminal window, go to the `tutorial-v1` repo and `cd sample-front-end`. From this directory you can start the frontend:

```
npm install
npm start
```

Then start your browser go to <http://localhost:3200/>

You should see a page that looks like the following:

![Pasted image 20230311141039.png](/files/z0IQlGSKsvpUIBcQBVYK)

When you click the login button the Metamask popup opens prompting you to connect with Metamask:

![Pasted image 20230311141155.png](/files/YqKFPHpN9dKXNcj6zOIb)

### Q: Why do I need to connect Metamask?

> **Answer**: In Web3, there's no centralized account management system. That means you're the only person to control your account. No one else can disable, remove, or alter your account. Metamask is an Ethereum browser wallet. When you login, the Metamask is used to sign a txn (short for transaction) using your own private key. This signed txn will be verified by the backend then the code will know it's you who's logging in. As long as you do not leak your private key, there is no way for anyone else impersonating you to login. In the future steps, all layer1 (blockchain) related [txn](/z_glossary/txn) will need Metamask to sign.

After connecting Metamask to this URL, you can see your account and a login button showing in the right top corner. Clicking the login button will bring up the login box:

![telegram-cloud-photo-size-1-4956649829228981200-y.jpg](/files/qMJ54SoMaMs68ynhSxo2)

This is the login authorization box. It lists all the rights that the TApp wants you to authorize.

* **Move** would allow this app to transfer your funds to other users.
* **In-app purchases** allows the app to spend your funds in relation to in-app functions and assets.
* **Manage investments** allows the app to buy / sell / transfer your token investments (i.e. those issued on a bonding curve).
* **Withdraw** would allow to move your layer-2 TEA to layer-1 (Ethereum).

Click login again to bring up the Metamask login again. Please double check the message in the box and make sure it's what you selected to authorize in the login box. In our case, it's sig\_consume.

![Pasted image 20230320203601.png](/files/FUsgGsCbTd6zHNIwDRbw)

Please pay attention on the message you're going to sign. In this case it's "sig". It's a placeholder for such a sample login. In other cases, this message has some real meaning, such as the authorization you give to the TApp. We'll get into more details in future steps.

After login, the UI jumps to the account profile page and shows your balance.

![Pasted image 20230312100636.png](/files/NVwRYmIYiddL8vA2Copx)

You can see you have a zero balance in your account. That's because everytime you start the dev-runner, the [state](/z_glossary/state) will be reset to the init state.

You can click the Faucet button to get 1000 free test tokens in your account.

These are all the features we added to the `login` branch.

## What happened under the hood?

After we built the sample-actor, a new sample-actor.wasm is copied to the dev-runner local/b-node folder. When we launch the dev-runner, the actor will be loaded into he [TEA-runtime](/z_glossary/mini-runtime) and activated. You should see something like the following in the log:

`client-bob | [enclave] INFO host_main{enabled_clients=["adapter", "libp2p", "third-api", "http"] app_id=0 tea_id="0000000000000000000000000000000000000000000000000000000000000000" conn_id="12D3KooWPLns5y2qhcLFb6WCYhTiT7gXnx9ubfUhcgNV8rdjCfee"}: INFO activate sample actor successfully`

This means the sample-actor is loaded and active. It's waiting for a request from the client.

Then we start the frontend and click the login button on the web page. The frontend generates a login message asking you to sign-in using Metamask. The signed message and login request is sent to the backend sample-actor to complete the login process. Once logged in, the frontend will receive an auth\_key similar to a session key in web2. It's the proof that the user has logged in and will be attached for almost every future request. Once the login is completed, the frontend jumps to the account profile page.

The account profile page sends a [query](/z_glossary/queries) request to sample-actor for the account balance. After a few seconds, the response of the balance information is received by the frontend and shown in the UI. You should see 0 in the balance because it's a new test state.

When you click the "Faucet" button, a transfer request is sent to the backend. In the local dev-runner mode, a special logic allows anyone to transfer 1000 TEA from the DAO\_RESERVE account for testing purposes. That's why you can get 1000 FREE TEA. Note that this won't happen in a non local dev-runner configuration. So you won't have such free gifts in Testnet or Production for sure.

Once the Faucet transfer has completed, you'll see your new 1000 TEA balance after the follow up balance query completes.

That's a recap of the steps that just happened. For more detailed information please see the code walkthrough articles in the sidebar.


# Sample-actor Code Walkthrough - Login Branch

In the `login` branch, the majorify of the logic is in the frontend. There are only a few code changes in the backend to handle the login and faucet logic. Let's walk through it all.

We moved the function to handle "say-hello" from `lib.rs` to a new file called `dfn.rs`. A new handler "faucet" has also been added. This is used to send a faucet [txn](/z_glossary/txn) when the user clicks the "faucet" button in the frontend.

```
use crate::error::Result;
use crate::api;
pub fn name_list() -> Vec<&'static str> {
	vec![
		"say-hello",
		"faucet",
	]
}

pub async fn map_handler(action: &str, arg: Vec<u8>, from_actor: String) -> Result<Vec<u8>> {
	let res = match action {
		"say-hello" => serde_json::to_vec("Hello world!").unwrap(),
		"faucet" => api::txn_faucet(arg, from_actor).await?,
		_ => vec![],
	};
	Ok(res)
}
```

When adding a new handler, make sure to also add the name to the `name_list`, because we'll need to let dfn::map\_handler dispatch the request to the coresponding handler.

In the future, almost all request handlers will be put here for easy organizing.

Let's take a look at where these functions are called, for example in `lib.rs`:

```
impl Handle<HttpRequest> for Actor {
	async fn handle(&self, req: HttpRequest) -> Result<Vec<u8>> {
		let from_actor = String::from_utf8(NAME.to_vec())?;
		let base_res = map_handler(&req.action, req.clone().payload, from_actor.clone()).await?;
		let cur_res = crate::dfn::map_handler(&req.action, req.payload, from_actor).await?;
		if cur_res.is_empty() && !base_res.is_empty() {
			return Ok(base_res);
		}
		Ok(cur_res)
	}
}
```

This is the most important function. The `base_res` is used to handle **default** behaviors that can be handled by the `tea_sdk::utils`. In this case, it's the login request.

So if the default handler is used and the `crate::dfn::map_handler` does not handle it (cur\_res is empty), then the base\_res is returned to the client.

If you want to override the default handler, you can define the handler function inside of dfn.rs, so that the cur\_res is no longer empty and it will be returned to the client.

In this case, we didn't handle the login request, instead the default login handler inside the `tea_sdk::utils` is used. That's why we can write almost zero code to get the login feature.

In our TEA SDK, there are many default handlers like login. For more details about the `tea_sdk::utils` please go to [tea\_sdk\_utils](/020_tutorial/040_add_login_feature/041_sample_actor_code_walkthrough/tea_sdk_utils).

You may also notice that the AddRequest handler is removed given it's no longer used in this and future steps.

A new api.rs is added, and in this step it's mainly for the txn\_faucet function.

```
pub async fn txn_faucet(payload: Vec<u8>, from_actor: String) -> Result<Vec<u8>> {
	let req: FaucetRequest = serde_json::from_slice(&payload)?;
	check_auth(&req.tapp_id_b64, &req.address, &req.auth_b64).await?;
	info!("Start faucet action...");

	let txn = TappstoreTxn::TransferTea {
	    token_id: tappstore_id().await?,
	    from: DAO_RESERVED_ACCOUNT,
		to: req.address.parse()?,
		amount: DOLLARS * 1000,
		auth_b64: req.auth_b64.to_string(),
	};

	request::send_tappstore_txn(
		&from_actor,
		"faucet_txn",
		&req.uuid,
		tea_sdk::serialize(&req)?,
		txn,
		vec![],
	)
	.await?;
	help::result_ok()
}
```

When the "faucet" request is received by the [actor](/z_glossary/actor), `crate::dfn::map_handler` will dispatch the function call to txn\_faucet. Inside this function, we first generate the req:

```
let req: FaucetRequest = serde_json::from_slice(&payload)?;
check_auth(&req.tapp_id_b64, &req.address, &req.auth_b64).await?;
  
```

then use `TappstoreTxn::TransferTea` to convert it to a txn. `request::send_tappstore_txn` is used to send such a txn. This txn is sent to the [state machine](/z_glossary/state_machine) and executed async.

Note we don't expect to get the execution result at this moment because all state machine nodes will handle async.

Please read the code carefully and understand each parameter.


# tea\_sdk\_utils

The tea sdk utills wraps a bunch of utilities that the developer will need to use to interact with the TEA system. The source code is at <https://github.com/tearust/sdk/blob/master/utils/wasm-actor-utils/src/client/types.rs>

Here's the list of functions:

* login: Used for user login
* query\_session\_key: to use the logged in user's session\_key. This session\_key is needed almost every time in order to contact the backend as the proof of user login.
* query\_result: To get the response from previous requests. This is because all requests to the backend will be handled async.
* queryHashResult: TODO://
* logout: logout
* query\_balance: query the account balance.
* query\_deposit: query the deposit balance.
* query\_asset:TODO://
* query\_allowance:
* query\_tapp\_metadata: Get TApp metadata.
* query\_err\_log: get error log.
* query\_system\_version: get system version.

Some of the account concepts might be unfamiliar to you, such as "balance, deposit, allowance". Please read the TEA Project tokenomics for more details.


# Sample Front-end Walkthrough - Login Branch

The sample-front-end has some major code changes from the `master` branch. This should be the only major change for the rest of the steps. The reason we've introduced these major changes is because we have put all commonly used utilities into this branch. In the future steps, major changes will be hapenning in the sample-actor backend.

This `login` branch is probably the best boilerplate that you can use to build your own TApp from because it has all major commonly used utiility features, such as login, fund transfer etc.

## Code structure

## Handle user login

When user clicks the Login button, the UI shows the LoginModal box. The login box VUE code is located in views/modals/LoginModal.vue. Please pay attention to the data:

```
data(){
    return {
      loading: true,
      form: {
        
      },
      // Node: please add authorizations here when needed
      // read: false,
      // withdraw: false,
      // consume: true,
      // move: true,
      // bonding_curve: false,
    };
  },
```

The `read, withdraw, consume, move, bonding_curve` are authorizations that the user needs to confirm which we [explained previously](/020_tutorial/040_add_login_feature). In this `login` step, there's no business logic to transfer or consume funds. So we can simply remove all authorization strings here (you can see that all of them are commented out). But in our future steps, such as `reward` branch, there would be fund transfer or consumption busienss logic. You will see `consume` and `move` are set to true. When those authorization strings are set to true, the end user may see the string in Metamask sign window.

This is important to let the end user know what types of authorization they should allow for the app. In case of any suspicious strings that aren't expected by the app, the end user can refuse to sign and login.

The js code to handle user login is in `src/layer2/user.js`

```
  async login(self, permission_str) {
    const address = self.layer1_account.address;

    const chain = await self.wf.layer1.getChain();
    if(chain.name === 'Offline'){
      throw('You did not install metamask wallet, please login with your email address.');
    }


    // thanks for https://github.com/polkadot-js/extension/issues/827
    const data = permission_str;
    console.log('permission_str => ' + permission_str);

    try {
      const layer1_instance = self.wf.getLayer1Instance();
      let [sig, pk, msg_bytes, msg] = await layer1_instance.signMessage(data);


      sig = sig.replace(/^0x/, '');
      let rs = await txn.txn_request('login', {
        tappIdB64: base.getTappId(),
        address,
        pk: utils.uint8array_to_base64(hexToU8a(pk)),
        data: msg,
        signature: sig,
      });
      rs = await txn.query_request('query_session_key', {
        tappIdB64: base.getTappId(),
        address,
      });

      if (rs.auth_key) {
        const user = {
          address,
          isLogin: true,
          session_key: rs.auth_key,
          expird_time: Date.now() + 1800 * 1000,
        };

        utils.cache.put(F.getUserId(address), user);
        await store.dispatch('init_user');

        base.top_log(null);

        self.$root.goPath('/account_profile');
        return true;
      }

    } catch (e) {
      // TODO handle error.
      throw e;
    }
  },

```

We first check if the chain name is available from the Metamask SDK. If it doesn't exist, we display an error and ask the user to install Metamask.

```
const chain = await self.wf.layer1.getChain();
    if(chain.name === 'Offline'){
      throw('You did not install metamask wallet, please login with your email address.');
    }
```

Then we generate a sig of the msg `permission_str` from Metamask.

```
const layer1_instance = self.wf.getLayer1Instance();
      let [sig, pk, msg_bytes, msg] = await layer1_instance.signMessage(data);


      sig = sig.replace(/^0x/, '');
```

This is how Metamask asks you to sign.

Once the signed data is received from Metamask, the next step would be sending a "login" request to the backend. The code looks like this:

```
     let rs = await txn.txn_request('login', {
        tappIdB64: base.getTappId(),
        address,
        pk: utils.uint8array_to_base64(hexToU8a(pk)),
        data: msg,
        signature: sig,
      });
```

`txn.txn_request` is widely used all over the frontend code whenever we want to send requests to the backend. Note the backend handle is always **async** so you shouldn't expect to get a response immediately. You'll always need to query the result using `await txn.query_request` as in the code below:

```
     rs = await txn.query_request('query_session_key', {
        tappIdB64: base.getTappId(),
        address,
      });
```

Once the response is received, the `auth_key` will be saved to the local cache. This auth\_key is very important, we'll need to attach this key to all future requests to the backend so that the backend will know the user has been logged in. If the auth\_key is either missing or expired, the user will be requested to login again. This is usually called "session time out" in the web2 world.

## Query account balance

Query account balance code is located in `src/layer2/user.js`

```
async query_balance(self, target = null, target_tapp = null,) {
    const session_key = F.checkLogin(self);

    const opts = {
      address: self.layer1_account.address,
      tappIdB64: base.getTappId(),
      authB64: session_key,
    };
    if (target) {
      opts.target = target;
      opts.targetTappIdB64 = target_tapp;
    }

    try {
      const rs = await txn.query_request('query_balance', opts);
      if (!rs.balance) {
        rs.balance = 0;
      }

      return rs ? utils.layer1.balanceToAmount(rs.balance) : null;
    } catch (e) {
      self.$root.showError(e);

      return 0;
    }

  },
  
```

First we'll need to get the login session key (the `auth_key` in the login session). `const session_key = F.checkLogin(self);` This session\_key will need to be attached to the request.

`opt` is the query\_balance request parameter. We we'll need to tell the backend the following query parameters:

* Which app am I querying. Every app has a different account system.
* Which address (account) am I querying.
* Session\_key. Used to verify that this user has logged in and has the right to query.

Then call query\_request to query.

\`const rs = await txn.query\_request('query\_balance', opts);

The function `utils.layer1.balanceToAmount(rs.balance)` is used to convert the number to human readable text.


# SQL

In this tutorial, we'll learn how to write SQL scripts in TApp development. We'll be using a decentralized task TApp as our example app where a task owner creates a task and anyone else can claim the task to work on by paying a deposit. Once the work is submitted and the task owner confirms the task is completed, the worker is paid back their deposit as well as the award amount for the task.

The business goal of this step would be:

* User can get free test token using the faucet.
* User can create a task which is stored in the database.
* User can edit a task then save changes.
* User can delete a task.
* User can list all tasks.

Being able to use SQL is a major advantage that TEA Project has over other web3 platforms. TEA Project is not a blockchain; it has distributed SQL instances in every state machine node. The **Proof-of-time** consensus can make sure all [nodes](/z_glossary/hosting_cml) reach the same [state](/z_glossary/state) (strong [consensus](/z_glossary/consensus)) after a time buffer elapses.

For developers, it's as simple as what they did in traditional web2 development as if there's an SQL database under the hood. The only difference would be that the changes will be taking effect after a time buffer. This time buffer is set to 3 seconds during the TEA Project beta. After this time buffer, the state change will be shown in your next query.

Although the step to get free test tokens should technically be in the next tutorial step (the state machine transfer), we'll leave the code in the `sql` branch simply because the user needs some tokens to pay gas.

## Understand the sample-txn-executor actor

You'll need to `git checkout sql` to switch to the SQL branch. You'll notice that a new folder `sample-txn-executor` has been added. This [actor](/z_glossary/actor) is called an "A-actor" internally. The previous `sample-actor` is called a "B-actor" internally. Although the official names for A-actor should be state machine actor and B-actor should be hosting actor. Just to be clear, some old documents will still use the old "A" and "B" node names.

Similar to 3-tier architecture in traditional web2 development, the hosting actor is the lambda function running inside the Web Server, while the state machine actor is running inside the [state machine](/z_glossary/state_machine) similar to a database stored procedure.

## Client <-> Hosting actor <-> State machine actor workflow

The common request -> response work flow would be as follows:

* Browser (client) sends requests to a hosting node.
* Hosting actor inside the hosting node handles the request.
* If the hosting actor sample-actor can't respond immediately, it will respond directly back to the client. The request -> response loop ends.
* If the hosting actor cannot respond immediately, it usually sends another txn to the state machine node. At the same time a UUID response is sent back to the browser (client). The client will know it has to query the result at a later time using the UUID.
* The state machine node receives the txn from the hosting node. The txn is queued in the Proof of Time conveyor, sorted and eventually executed in turn by the sample-txn-executor actor.
* The sample-txn-executor may change the state in the state machine in case of a [command](/z_glossary/commands), or not change the state at all in the case of a [query](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/query.md). The state machine will update the hosting node with the result, either success or an error.
* The client will periodically query the hosting node for the result of the previous request using the UUID.
* The hosting node will eventually get the update from the state machine node along with the result associated with the UUID. After the hosting node has the result, the next client query will receive the response back of the UUID and the result.
* The browser (client) will get a notification that the txn has been executed along with the execution status, either successful or an error.

In this step, we'll use SQL as an example to demo how this workflow works. All other types of reqeusts will work the same way.

## Build the "sql" branch

First you'll need to switch to the `sql` branch of `tutorial-v1`: `git checkout sql`

If you get an error about `sample-actor/Cargo.lock` you can delete that file. Alternately you can also do `git checkout —force sql` if there are any uncommited changes preventing you from switching branches.

In your local `tutorial-v1` repo, you'll need to build the two wasm files that are located in the `sample-actor` and `sample-txn-executor` folders. These build scripts are located at the following locations:

* `sample-actor/build.sh`
* `sample-txn-executor/build.sh`

The target wasm files will be copied to the `dev-runner` repo, specifically to `/local/b-node` and to `dev-runner/local/a-node` respectively. Note: unlike the `sample_actor.wasm` file that goes to the **b-node**, this `sample_txn_executor.wasm` goes to the **a-node**. This is because it runs in the state machine.

Start the dev-runner by running `docker compose up`.

Back in your `tutorial-v1` local folder, start the front-end by running the following commands from the `sample-front-end` folder:

```
npm install
npm start
```

## Admin page and initialization

Visiting <http://localhost:3200>, you should see:

![Pasted image 20230317093125.png](/files/FuviplwdfxVMtJfR3Icx)

[!](https://github.com/tearust/t-rust/blob/master/docs/Pasted_image_20230315093816.png)

From the new **Admin** page, click the two buttons "Init AppToken" and "Init TApp db" to simulate deploying the TApp.

There are two new pages in our app, a **Task** page and an **Admin** page. The new Admin page is required because we're running a local development environment called Dev-Runner. We want to use the two buttons "Init AppToken" and "Init TApp db" to simulate the Deploy and Init TApp steps in the real Developer Portal. The Dev-Runner is a simplified version of the TEA-Runtime. There's no Developer Portal built-in, but we still need to initialize the TApp token and TApp database before a TApp can be used.

So please always click those two buttons in the Admin page whenever:

* It's the first time you're running this TApp in Dev-Runner.
* Or everytime after you've deleted the `.tokenstate` local state persistent storage.

You'll need to delete the `.tokenstate` everytime you modify your code that's related to any state or SQL database. Consider it a "purge" operation that resets the whole state making the SQL databse **brand new**. That's why you'll need to initialize it before using your TApp. In the real production environment, there won't be such a "refresh". It'll only be initialized once at your TApp's initial deploy.

You'll only need to run those two initialization tasks once. If you click it the second time, you'll be prompted with an error but it won't cause any damage at all. So if you're not sure if you've initialized it or not, feel free to click them again, and take any generated errors as a harmless sign you've already completed these steps.

## Run the "sql" branch

But before we try the latest features, let's test the existing features from the previous "master " and "login" steps, making sure they're still running without any breaking changes.

"Hello world" still works:

![Pasted image 20230315093943.png](/files/SwzhdaKhIqnW0DlYiROa)

Now login as you did in the previous step. Use the "faucet" to add 1000T to your account which should be enough for testing purposes. Now your account should look like this:

![Pasted image 20230315094045.png](/files/axqFBQzc61lo8uOx79ee)

Great, your previous steps are still running as expected. Now move to the new features by clicking "Task".

The UI is very simple, just add new tasks. You should see them in the list.

![Pasted image 20230315094303.png](/files/5Iqds4AsbXJLO6DXJcMx)

You can try to remove tasks as well, and it should work as expected.

You can logout and login again to verify your previous stored tasks are still there. So your work has been stored into the SQL database in our state machine.

Great! Now let's move on to the code walkthrough and figure out how it works.


# Sample Txn Executor

Let's focus on the sample-txn-executor folder in this article. This is a brand new folder and it'll build the wasm file that will be loaded into the [state machine](/z_glossary/state_machine) .

## Folder structure

All actors have the same folder structure:

* codec contains all the type definitions.
* impl contains all the logic.

One thing to mention and likely overlooked is the last line in the build.sh file: `cp -r target/wasm32-unknown-unknown/release/sample_txn_executor.wasm ../../dev-runner/local/a-node/`

You may have already noticed that the destination folder is an **a-node** instead of a **b-node** of the sample-actor.

## Codec

In the txn.rs file, we have Task, Status, And Txns definitions.

```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Task {
    pub creator: Account,
    pub subject: String,
    pub price: Balance,
    pub required_deposit: Balance,
    pub status: Status,
    pub worker: Option<Account>,
}
```

Task is the model if you're familar with the MVC concept. This object will be mapped to the SQL database for CRUD.

Please note the types "Account, Balance". Those are predefined TEA Project types. You'll use them a lot.

Every task will need to have each of the following:

* creator: who creates this task, who's also the owner. It's an Account type.
* subject: the title of this task. Such as "Buy me a beer!"
* price: The worker who has done this task successfully will receive the reward price from the owner/creator.
* required\_deposit: The worker who takes a task will need to pay the deposit. If they fail to complete the task, the deposit will be slashed and rolled into the price. The final successful worker will take the augmented price.
* status: See below.
* worker: None if no one takes a particular task, or the worker who is currently working on or completes a particular task.

The status is:

```
#[derive(
    Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, AsRefStr, EnumString, Display,
)]
pub enum Status {
    New,
    InProgress,
    WaitForVerification,
    Done,
}
```

Their names explain the meaning.

The most important concept is [txn](/z_glossary/txn):

```
#[derive(Debug, Clone, Serialize, Deserialize, AsRefStr, Display)]
pub enum Txns {
    Init {},
    CreateTask {
        task: Task,
        auth_b64: String,
    },
    DeleteTask {
        subject: String,
        auth_b64: String,
    },
    VerifyTask {
        subject: String,
        failed: bool,
        auth_b64: String,
    },
    TakeTask {
        subject: String,
        worker: Account,
        auth_b64: String,
    },
    CompleteTask {
        subject: String,
        auth_b64: String,
    },
}

```

Those Txn types are the Transaction objects that the hosting nodes (where the b-actor is running) sends to the state machine (A-actor) to handle. It's similar to the stored procedures inside of databases of the web2 era.

Every txn will have the parameters, and the execution logic of these txn will be inside the `impl` folder.

In the lib.rs file, we have defined Requests and Responses as we did in our last step.

There's a new struct TaskQueryRequests:

```
#[derive(Debug, Clone, Serialize, Deserialize, TypeId)]
pub struct TaskQueryRequest {
    pub creator: Option<Account>,
    pub worker: Option<Account>,
    pub status: Option<txn::Status>,
    pub subject: Option<String>,
}
```

and a response that returns a string of tasks. The Task has a type of `txn::Task`.

TaskQueryRequests are used in Queries from the hosting nodes. When a B-actor wants to query a list of Tasks they can use these conditions.

Note: In TEA Project future versions, a local state cache will be provided to the hosting nodes. So in most cases, there's no need for the hosting node to query the list of Tasks from the state machine, which will ultimately reduce the cost.

## Impl

### manifest.yaml added new access

Compared with the previous steps, you'll notice there are lots of new access items added:

```
access:
  - tea:adapter
  - tea:statereceiver
  - tea:tokenstate
  - tea:replica
  - tea:crypto
  - tea:nitro
  - tea:env
  - tea:keyvalue
  - com.tea.keyvalue-actor.manager
  - com.tea.tappstore-actor
  - com.tea.ra-actor
```

You can go to the developer documentation for the usage for each provider actor. Because the `sql` branch has added many system features such as fund transfer, sql access, storage etc, it's required to claim the list in the manifest. Otherwise, the access will be banned by the tea-runtime.

### tables.sql is a standard sql script

This is the first time you'll find a non rs file in the src folder. This is a standard SQL file. It's nothing but a script to create a table.

```
CREATE TABLE Tasks
(
  subject						TEXT UNIQUE,
  creator						TEXT,
  worker						TEXT NULL,
  status						TEXT,
	price 						TEXT,
	required_deposit	TEXT
);
```

To simplify our tutorial, we didn't use any 3rd party MVC tools to build sql scripts for us. We use pure SQL which is easily understood by developers. When you're building your own TApp, feel free to use whatever existing web2 tools you're familiar with. They should all work well with the TEA Project.

You may be wondering where the other SQL scripts are located? We should use Create, Read, Update, Delete scripts. Well, they're inside the rs code as string and you'll see them soon.

### Add new errors into error.rs

Because we're now handling the txn, there will be errors during txn execution. We need to define them inside of `error.rs`:

```
#[derive(Debug, Error)]
pub enum TxnErrors {
    #[error("Account {0:?} is not allowed to operate task")]
    InvalidAccount(Account),

    #[error("Task {0} already token by {1:?}")]
    TaskInprogress(String, Account),

    #[error("Task can only be deleted when status is new or done")]
    DeleteTaskFailed,

    #[error("Task can only be verified when status is wait for verification")]
    VerifyTaskFailed,

    #[error("Task can only be taken when status is new")]
    TakeTaskFailed,

    #[error("Task can only be finished when status is in process")]
    CompleteTaskFailed,
}
```

Note, don't forget to add to the define\_scope macro too:

```
define_scope! {
    Impl: SampleActor {
        HttpActionNotSupported => @SampleActor::HttpActionNotSupported;
        TxnErrors => @SampleActor::TxnErrors;
    }
}
```

### Execute transactions in txn.rs

Most of the logic is here inside the txn.rs function `txn_exec`.

You can see all txns defined in the codec have been handled in a `match` branch, then return a commit\_ctx. The commit\_ctx is a Context type which records all changes during the txn execution. However, before the commit\_ctx is finally commited at the last of the `txn_exec` function, no actual changes happened in the state. That means, at any time, if the execution failed for whatever reason, the state will **NOT** be changed.

Let's use CreateTask as an example:

```
        Txns::CreateTask { task, auth_b64 } => {
            check_account(auth_b64, task.creator).await?;
            let glue_ctx = new_gluedb_context().await?;
            create_task(tsid, task).await?;
            CommitContext::new(
                ctx,
                glue_ctx,
                None,
                None,
                decode_auth_key(auth_b64)?,
                txn.to_string(),
            )
        }
```

This txn is very simple and only runs SQL scripts. Before any real business logic, the line of `check_account` will make sure the user is the `task.creator` and isn't impersonated. If Alice is trying to create a task but claims the creator is Bob, this check will fail. If this check passes, the next `new_gluedb_context()` will generate a new glue\_ctx. It also starts an SQL Transaction. If anything failed before the commit, no change will be written to the SQL database.

The SQL scripts is inside the `create_task` function.

```
pub(crate) async fn create_task(tsid: Tsid, task: &Task) -> Result<()> {
    exec_sql(
        tsid,
        format!(
            "INSERT INTO Tasks VALUES ('{}','{:?}',NULL,'{}','{}','{}');",
            task.subject,
            task.creator,
            Status::New,
            task.price,
            task.required_deposit
        ),
    )
    .await
}
```

The function `exec_sql` will run the SQL scripts.

In TEA Project, the SQL engine is [GlueSQL](https://github.com/gluesql/gluesql). This is not a fully featured SQL engine, so please review our documentation entry for [GlueSQL](/z_glossary/gluesql) ) for more details. In our tutorial, we only use very basic SQL features. For example, we didn't use auto increase ID but instead used the subject as ID. This isn't ideal but is good enough to demonstrate the logic. Teaching SQL is not the purpose of this tutorial.

Please make sure `sql_init` is called at `Txns::Init`.

```
        Txns::Init {} => {
            sql_init(tsid).await?;
            CommitContext::ctx_receipting(ctx, txn.to_string())
        }
```

TODO:// GOD\_MODE\_AUTH\_KEY will be replaced later

## lib.rs

Lib.rs is the entry point of the whole sample-txn-executor. It has the same structure as the sample-actor.

First, we should also list all [txns](/z_glossary/txn) that we can handle:

```
impl Handles<()> for Actor {
    type List = Handle![
        Activate,
        PreInvoke,
        HttpRequest,
        TaskQueryRequest,
        ExecTxnCast,
        ActorTxnCheckMessage
    ];
}
```

**HttpRequest** is a special request that we created for the local dev-runner only. In the real production environment this will not exist. The purpose of adding http requests to the sample-txn-executor is for easy CURL / Postman testing. In the real production environment, all txns are sent from the hosting nodes (B-actors). You have to have a B node to test the Txns, which causes additional complexities. Using this "mock" http request, you can write your own local test code. Especially when dealling with SQL, it's hard to test SQL in unit tests.


# Sample Actor

Because most of the newly added logic stays in the newly added sample-txn-executor, the sample-actor only adds a new request handler. Those handlers do nothing but receive and relay to the [state machine](/z_glossary/state_machine) because all of them are supposed to be handled in the state machine SQL instances.

## dfn.rs

```
pub fn name_list() -> Vec<&'static str> {
	vec![
		"say-hello",
		"faucet",
		"create_task",
		"query_task_list",
		"delete_task",
		"verify_task",
		"take_task",
		"complete_task",
		"init_db",
		"init_token",
	]
}

pub async fn map_handler(action: &str, arg: Vec<u8>, from_actor: String) -> Result<Vec<u8>> {
	let res = match action {
		"say-hello" => serde_json::to_vec("Hello world!").unwrap(),
		"faucet" => api::txn_faucet(arg, from_actor).await?,
		"create_task" => api::create_task(arg, from_actor).await?,
		"query_task_list" => api::query_task_list(arg, from_actor).await?,
		"delete_task" => api::delete_task(arg, from_actor).await?,
		"verify_task" => api::verify_task(arg, from_actor).await?,
		"take_task" => api::take_task(arg, from_actor).await?,
		"complete_task" => api::complete_task(arg, from_actor).await?,
		"init_db" => api::init_db(arg, from_actor).await?,
		"init_token" => api::init_token(arg, from_actor).await?,

		_ => vec![],
	};
	Ok(res)
}
```

You see that the handler is just a dispatcher, and the logic will be in the `api.rs` file.

## api.rs send requests

Let's use the delete\_task as an example:

```
pub async fn delete_task(payload: Vec<u8>, from_actor: String) -> Result<Vec<u8>> {
	let req: DeleteTaskRequest = serde_json::from_slice(&payload)?;
  check_auth(&req.tapp_id_b64, &req.address, &req.auth_b64).await?;
	info!("Delete Task action...");

	let txn = Txns::DeleteTask {
    subject: req.subject.to_string(),
		auth_b64: req.auth_b64.to_string(),
	};

	request::send_custom_txn(
		&from_actor,
		"delete_task",
		&req.uuid,
		tea_sdk::serialize(&req)?,
		tea_sdk::serialize(&txn)?,
		vec![],
		TARGET_ACTOR,
	)
	.await?;

	help::result_ok()
}
```

We first created a DeleteTask txn, then use `send_custom_txn` utility to send it to the state machine.

When using the send\_customer\_txn you'll need to specify the from\_actor (which in this case is the **sample-actor**) and the txn name. The req.uuid is used for the client to [query](/z_glossary/queries) the [txn](/z_glossary/txn) execution result at a later time. The TARGET\_ACTOR is the name of the receiving A actor, it's "someone.sample\_txn\_executor". If you're wondering where this name comes from, you can find it from the mainifest.yaml in `sample-txn-executor/impl/manifest.yaml`. This is how the TEA Project locates and identifies every [actor](/z_glossary/actor).

## check\_auth

You may have noticed the `check_auth` in function `create_task`, but you didn't see such a line in the function `query_task_list`. This is because anyone can query the task list even without login, but then one will only be able to create a task with the creator set to be one's own address. Of course, a user who's not logged in cannot create a task. So the check\_auth is used to guard against this.

Auth control is a large topic and in our tutorial we only explain how to use it. For a detailed discussion please go to the developer documentation.

`check_auth(&req.tapp_id_b64, &req.address, &req.auth_b64).await?`

This function will verify that req.auth\_b64 matches the req.address from the recorded user's login data. If it fails, an error would be thrown. Basically, the auth\_b64 is a session key. The TAppStore actor stores session information using this auth\_b64 as a key. The client needs to keep the auth\_b64 in safe storage. It'll be hard for a malicious hacker, as long as they don't have this session key, to impersonate a real user. Note that all the communication between browser and any TEA nodes are encrypted to prevent middle man and replay attacks.

## Faucet

Faucet is a special feature that only lives in the local dev-runner. The developer needs some test tokens even during local testing. So we make a faucet button function to dispense 1000 free test token from DAO\_RESERVE. Of course this will not be the case in the testnet or production.

Faucet request is handled by `"faucet" => api::txn_faucet(arg, from_actor).await?,`.

In `api.rs`:

```
pub async fn txn_faucet(payload: Vec<u8>, from_actor: String) -> Result<Vec<u8>> {
	let req: FaucetRequest = serde_json::from_slice(&payload)?;
  check_auth(&req.tapp_id_b64, &req.address, &req.auth_b64).await?;
	info!("Start faucet action...");

	let txn = TappstoreTxn::TransferTea {
    token_id: tappstore_id().await?,
    from: DAO_RESERVED_ACCOUNT,
		to: req.address.parse()?,
		amount: DOLLARS * 1000,
		auth_b64: req.auth_b64.to_string(),
	};

	request::send_tappstore_txn(
		&from_actor,
		"faucet_txn",
		&req.uuid,
		tea_sdk::serialize(&req)?,
		txn,
		vec![],
	)
	.await?;
	help::result_ok()
}
```

The main logic is wrapped into the `TappstoreTxn::TransferTea` function.

TAppStore is the most important system actor that handles most system calls. You can get more information about it from the developer documents. In this step, we can see it requests transferring 1000 T from DAO\_RESERVE to the current login user. The token\_id is TAppStore not this TApp's id. This is very important because all TEA token in the layer2 will be stored under the token\_id == TAppStore. If the token\_id == my\_new\_build\_tapp, the currency is not TEA, but your own layer2 token (e.g. my\_sample\_task\_coin).

There are two functions we're not going to explain here: they are `init_db` and `init_token`. They're not a part of the real production environment. We need them purely because we need to simulate initializing the TApp state and database in the local development environment. These tasks will be done by the Developer portal in the real environment.


# Sample Front-end

Although there are a lot of UI changes here, the under the hood changes are minimal. And most of them are just pure web front end code so we don't need to explain those. So let's focus on the logic related code in `views/TaskMain.vue`.

## Query tasks

```
    async refreshList(){
      this.$root.loading(true);
      const list = await layer2.task.queryTaskList(this);
      this.list = list;
      this.$root.loading(false);
    },
```

Follow the queryTaskList to the task.js

```
  async queryTaskList(self){
    const rs = await txn.query_request('query_task_list', {
      address: self.layer1_account.address,
    });
    return _.map(rs.list, (item)=>{
      try{
        item.price = utils.layer1.balanceToAmount(item.price);
        item.deposit = utils.layer1.balanceToAmount(item.required_deposit);
      }catch(e){
        item.price = utils.layer1.balanceToAmount(utils.toBN('0x'+item.price).toString());
        item.deposit = utils.layer1.balanceToAmount(utils.toBN('0x'+item.required_deposit).toString());
      }
      return item;
    });
  }
```

The function txn.query\_request is the utility that does most of the heavy lifting. We've explained this utility and others like it before.

## Create New Task

In TaskMain.vue:

```
    async createNewTask(){
      try{
        await layer2.task.createNewTask(this, {}, async (rs)=>{
          this.$root.success("create task success");
          await this.refreshList();
        });
      }catch(e){
        this.$root.showError(e);
      }
    },
```

Similiarly, we dive into task.js:

```
async createNewTask(self, param={}, succ_cb){
    const session_key = user.checkLogin(self);

    const tappId = base.getTappId();
    self.$store.commit('modal/open', {
      key: 'common_form',
      param: {
        title: 'Create Task',
        text: ``,
        props: {
          subject: {
            type: 'Input',
            required: true,
            label: 'Task subject',
          },
          price: {
            type: 'number',
            default: 10,
            label: 'Price (TEA)'
          },
          required_deposit: {
            type: 'number',
            default: 20,
            label: 'Deposit (TEA)',
          }

        },
      },
      cb: async (form, close) => {
        self.$root.loading(true);
        const price = utils.layer1.amountToBalance(form.price);
        const required_deposit = utils.layer1.amountToBalance(form.required_deposit);

        const param = {
          address: self.layer1_account.address,
          tappIdB64: tappId,
          authB64: session_key,
          price: utils.toBN(price).toString(),
          requiredDeposit: utils.toBN(required_deposit).toString(),
          subject: form.subject,
        };

        try {
          await txn.txn_request('create_task', param);
          self.$root.success();
          await succ_cb();
        } catch (e) {
          console.error(e);
          self.$root.showError('Create task failed.');
        }
        close();
        self.$root.loading(false);

      }
    });
  },
```

First we get the session\_key. This is used as Auth\_b64 that we explained before, and will be referenced as `authB64: session_key` later.

A modal window will then open up showing a form where the user can input the content. Once commited, it will call the `cb` callback function. This callback function gathers all input task parameters, then sends them back via `txn.txn_request`. After that, we close the modal and clear the Loading backdrop.

## Other operation: delete, task, complete

These operations follow the same pattern but are even simpler.

## Summary

So you may have noticed the pattern we used in the front end.

It will be either a query\_request or a txn\_request. This is exactly the same as we 've done for more than a decade in traditional web2 development. We've worked hard to make the TEA Project a smooth onramp from web2 to web3.


# Reward Fund Transfer

## Overview

In this tutorial, we we'll learn how to transfer funds.

This step continues to use the decentralized task app that was described in the previous `sql` branch of the tutorial. We're going to use a specific business workflow for this branch of the tutorial as follows:

* After owner creates a task, another person called "absent-minded" will try to work on this task. "Absent-minded" takes this task and clicks "complete" when done.
* The owner verifies that the worker hasn't completed the task to specification. So the owner "rejects" the task.
* "Absent-minded" loses their deposit.
* The third user called "hard-worker" takes the same task and clicks "complete" when done.
* The owner verifies hard-worker's work is successfully done and clicks the "Confirm" button.
* The winner takes the price and the absent-minded's deposit.
* The task is done.

We'll learn in this walkthrough how to transfer funds between users of this task app based on the business logic.

## Build the 'reward' branch

As we've done several times in previous steps, we switch branches by running `git checkout reward` to the reward branch. Next build the two sample-actor and sample-txn-executor wasm files. They'll be copied to the **dev-runner local/a-node** and **local/b-node** folders.

The build scripts are in the following locations of the `tutorial-v1` repo:

* `sample-actor/build.sh`
* `sample-txn-executor/build.sh`

In order to clean up the [state](/z_glossary/state) data from previous steps, make sure you delete the `.tokenstate` directory in the `dev-runner` repo before launching the docker container. This will make dev-runner start with a fresh state.

Start dev-runner by running `docker compose up` from the root of the dev-runner directory.

Now from the `sample-front-end` directory of the `tutorial-v1` repo, run the following commands:

```
npm install
npm start
```

## Initialization steps in the browser

Now that the backend server is running, we'll need a few initialization steps before we can use the fund transfer function in our task TApp. The first step is to access the TApp in your browser by navigating to <http://localhost:3200>.

### 1. Init the TApp

Because this is a brand new state, please make sure you click the Init TApp token and Init TApp db buttons located in the **Admin** page before doing anything else.

![](https://user-images.githubusercontent.com/86096370/227608431-89da24e9-03d6-4e91-a28e-e14f63d02952.png)

### 2. Login to TApp

Now you can login to the TApp by clicking the login button in the upper right of the browser to spawn the Metamask modal window to login to the app.

### 3. Use the faucet

Your account has no TEA when beginning from a fresh state, so you'll need to use the **Faucet** button to load your account with some TEA. Note that this sends 1000 T to your layer2 account, and you don't need to be logged in with Metamask (layer1) to do this step.

![](https://user-images.githubusercontent.com/86096370/227608440-e8c2de65-149a-4de1-8051-f19028f7551b.png)

### 4. Set spending limit

Next you'll need to set the spending limit for the TApp before using it. Each TApp in the TEA Project has a spending limit that is set by the user to ensure that the TApp's business logic can withdraw user funds only up to that amount.

![](https://user-images.githubusercontent.com/86096370/227608436-80601f38-e2a4-4211-b21c-677d8e782265.png)

## Test the business logic

Now that we're ready to use the TApp, let's first go through the design of the business logic.

**User A** as the owner creates a task. You'll be playing the role of the task creator and of two different task workers for this section of the tutorial, which means you'll need to have three different Metamask accounts. After using the faucet and setting the spending limit for the owner account, you can now log out of the owner account and switch to the second user (we call them "absent-minded") in your Metamask.

Because absent-minded is a new user, they have zero balance now. In order to continue, use "Faucet" add 1000 TEA to their account and also set the spending limit for the app.

Then switch to the Task page where you'll find the UI has a "take" button as shown below:

![Pasted image 20230317091008.png](/files/FGpYsE96egjYsWoo0AR7)

This task is created by the owner, so as a worker, "absent-minded" can take this task.

After clicking "take", absent-minded is now the worker for this task. We'll simulate that this worker has done some work, so go ahead and click "Complete".

![Pasted image 20230317091258.png](/files/rnTyMI8uXtpVZrQ7mXyO)

At this time, user absent-minded's balance changes from 1000 to 995.

![Pasted image 20230317091328.png](/files/cxF0YfTanupp66JfrbMZ)

That's because by taking this task, the user will need to pay 5 T as a deposit. In the next step, if their work was accepted by the owner, they would take the 5T deposit back as well as the 10T task reward.

Now let's log out as absent-minded, and re-login with the Owner account.

We can see the task has two buttons: "Confirm" and "Reject".

![Pasted image 20230317091629.png](/files/szAEWvSzwBUPHfBcFfG6)

In our demo, we assume that user "absent-minded" somehow mismanaged the task and that the owner isn't satisfied, so you as the owner will go ahead and click "Reject". Note, as a demo, we assume everyone is honest. We may release a **secure oracle** feature to take such decisions out of human control, but that would potentially be in a future version of this tutorial.

After rejection, absent-minded lost their 5T deposit. The task status is set back to "new". Anyone can take this task and the winner will take 10+5=15T.

Now logout as the owner and switch to the third user account. This person's name is "hard-worker". Hard-worker will login, and also add 1000T test token using the faucet as well as setting the spending limit for the app. Again follow the same steps to take the task, and click the complete button. Again, log out as hard-worker, and login as owner.

This time, the owner is satisfied with the work of hard-worker. You as the owner will thus click "Confirm".

This task is "Done". To verify if the user "hard-worker" has received the 15T reward, you can logout of the owner account and log back in to hard-worker's account to check their balance. You should find roughly 1015 T in their account balance (1015T less any small gas fees).

![Pasted image 20230317092248.png](/files/BRXCgIEbBA3YlnvRnOMs)

So the workflow matches our expectation.

## No changes in sample-actor

There are no major changes for the **sample-actor** project when we went from the `sql` step to `reward` step. There are a few updates on the **sample-front-end** project, but all of them are standard javascripts front end code changes with not too much relationship to our funding transfer feature. We'll skip the detailed explanation, please go to the source code at `src/layer2/task.js` to read the code yourself.


# Sample Txn Executor

In the newly added `account.rs` file we handle the following txns:

* deposit\_for\_task: Pay deposit when taking a task.
* rollback\_deposit: Move the deposit to the owner in case of "reject" operation.
* reward\_owner: The successful worker takes the reward.

All the function code is straightforward and follows the same pattern:

* Input a `mut ctx`.
* Get the amount as well as payer and payee addresses.
* Call the `move` or `cross_move` function to transfer funds.
* **ctx** is mutable, so it contains all state changes. The caller will handle the ctx.

Let's move to the caller, the txn.rs. We use the TakeTask as an example, but all others txns follow the same pattern:

```
Txns::TakeTask {
            subject,
            worker,
            auth_b64,
        } => {
            let task = task_by_subject(subject).await?;
            if task.status != Status::New {
                return Err(TxnErrors::TakeTaskFailed.into());
            }
            if let Some(worker) = task.worker {
                return Err(TxnErrors::TaskInprogress(task.subject, worker).into());
            }
            check_account(auth_b64, *worker).await?;
            let glue_ctx = new_gluedb_context().await?;

            let (tappstore_ctx, ctx) =
                account::deposit_for_task(tsid, base, *worker, task.required_deposit, ctx).await?;
            take_task(tsid, subject, *worker, task.required_deposit).await?;
            CommitContextList {
                ctx_list: vec![
                    CommitContext::new(
                        ctx,
                        glue_ctx,
                        None,
                        None,
                        decode_auth_key(auth_b64)?,
                        txn.to_string(),
                    ),
                    CommitContext::ctx_receipting(tappstore_ctx, txn.to_string()),
                ],
                ..Default::default()
            }
        }
```

First, get the task. If the task status is not "new" then throw an error because only new tasks can be taken.

If the task has a worker, throw an error because the task has someone working on it.

`check_account(auth_b64, *worker).await?;` guard the current login user as the input worker parameter.

`let glue_ctx = new_gluedb_context().await?;` starts an SQL transaction. We should use this preface line everytime we run or process any SQL transactions.

```
let (tappstore_ctx, ctx) =
                account::deposit_for_task(tsid, base, *worker, task.required_deposit, ctx).await?;
```

This function `deposit_for_task` has a `ctx` input and also outputs `tappstore_ctx` and `ctx`. This is very important. `Ctx` is the object that records all the changes the code logic "should" apply to the state. But until commited, the changes are only stored in `ctx` without actually modifying the state. If anything is wrong during the `ctx` execution, the code can simply throw an error and return, and no changes will be applied to the state (i.e. the state remains unchanged).

In order to keep all changes in `ctx` and commit at once to modify `ctx` at a later time, ALL functions will have `ctx` as an input as well as returning `ctx` to the caller.

In this function, the output has another `tappstore_ctx` variable rather than the sole input `ctx`. That's because the tappstore's state will be changed during the execution. We'll need to commit both ctx for this TApp AND the context of TAppStore. Why will we change the state of the TAppStore? It's because the deposit and TEA account balance are stored in the TAppStore state. This is designed for easier TApp development. In most cases, the TApp doesn't need to maintain a TEA token state in their own state. Nor does the user need to topup TEA tokens to all the TApps they're using.

`take_task` is a function to execute sql scripts. The code is in sql.rs:

```
pub(crate) async fn take_task(
    tsid: Tsid,
    subject: &str,
    worker: Account,
    required_deposit: Balance,
) -> Result<()> {
    exec_sql(
        tsid,
        format!(
            r#"
            UPDATE Tasks SET 
                status = '{}',worker = '{worker:?}' 
                WHERE subject = '{subject}';
            INSERT INTO TaskExecution VALUES (
                '{subject}', '{worker:?}', '{required_deposit}'
            );
               "#,
            Status::InProgress
        ),
    )
    .await
}
```

This function is used to change the table to mark that a worker has taken a specific task.

Lastly, at the end of this [txn](/z_glossary/txn), return the CommitContextList:

```
            CommitContextList {
                ctx_list: vec![
                    CommitContext::new(
                        ctx,
                        glue_ctx,
                        None,
                        None,
                        decode_auth_key(auth_b64)?,
                        txn.to_string(),
                    ),
                    CommitContext::ctx_receipting(tappstore_ctx, txn.to_string()),
                ],
                ..Default::default()
            }
```

All matching branches in the txn executor will need to return such a `CommitContextList`. This list includes all the changes during the execution. Eventually, these changes will be applied using a Commit function so that the state and SQL database can be permanently changed.

For the details of CommitContextList, please refer to the Developer Documents.

## Other minor changes

In `error.rs`, you can find a few newly added errors that are self-explanatory.

We won't describe `table.sql` because these are all standard SQL scripts, for indexing, table creating etc. SQL is not in the scope of this tutorial.


# Retweet Task

## Retweet Task App

In this tutorial, we'll tweak our existing Task TApp such that the only kind of task available is to retweet (quote tweet) a tweet. Task creators will assign this task for others to quote tweet their desired tweet in an effort to make it go viral. This could be useful for developers who want their tweets seen by more people as quote retweets will show up in the other user's Twitter timeline.

An important difference with the previous version is that the reward no longer requires human intervention to release the funds. The task worker enters their quote tweet url which can be checked by API if it's in fact a quote tweet. If it passes the api check, then the funds are automatically released to the task taker.

## Business Workflow of Retweet Task

The business workflow for this branch is as follows:

* The task creator creates a task by entering their desired tweet they want quote retweeted. In addition, they also add in a reward amount for successful task completion and a deposit they require from the task taker.
* The task taker must quote retweet the source tweet and enter the url of their quote retweet in the task taker's modal window.
* Clicking confirm will send an api request to Twitter and confirm whether the entered url is in fact a quote retweet of the source tweet url.
* If the api confirms success, then the task taker gets the bounty as well their initial deposit back.
* If the api confirms that the quote tweet isn't of the original tweet, then the task taker's bounty is slashed and is added to the bounty for the task. The task then goes back into the available task queue and is available for anyone to take.

## Build the 'http' Branch

As we've done several times in previous steps, we switch branches by running `git checkout http` to switch to the **http** branch. Next we'll build the two sample-actor and sample-txn-executor wasm files. They'll be copied to the **dev-runner local/a-node** and **local/b-node** folders.

The build scripts are in the following locations of the `tutorial-v1` repo:

* `sample-actor/build.sh`
* `sample-txn-executor/build.sh`

Start dev-runner by running `docker compose up` from the root of the dev-runner directory.

Now from the `sample-front-end` directory of the `tutorial-v1` repo, run the following commands:

```
npm install
npm start
```

## Initialization steps in the browser

Now that the backend server is running, we'll need a few initialization steps before we can use the fund transfer function in our task TApp. The first step is to access the TApp in your browser by navigating to <http://localhost:3200>.

### 1. Init the TApp

Because this is a brand new state, please make sure you click the Init TApp token and Init TApp db buttons located in the **Admin** page before doing anything else.

![](https://user-images.githubusercontent.com/86096370/227608431-89da24e9-03d6-4e91-a28e-e14f63d02952.png)

### 2. Login to TApp

Now you can login to the TApp by clicking the login button in the upper right of the browser to spawn the Metamask modal window to login to the app.

### 3. Use the faucet

Your account has no TEA when beginning from a fresh state, so you'll need to use the **Faucet** button to load your account with some TEA. Note that this sends 1000 T to your layer2 account, and you don't need to be logged in with Metamask (layer1) to do this step.

![](https://user-images.githubusercontent.com/86096370/227608440-e8c2de65-149a-4de1-8051-f19028f7551b.png)

### 4. Set spending limit

Next you'll need to set the spending limit for the TApp before using it. Each TApp in the TEA Project has a spending limit that is set by the user to ensure that the TApp's business logic can withdraw user funds only up to that amount.

![](https://user-images.githubusercontent.com/86096370/227608436-80601f38-e2a4-4211-b21c-677d8e782265.png)

Note that the last 2 steps (using the faucet and setting the spending limit) are only available in the local environment and these buttons won't exist in the real deployment of the app.

## Test the business logic

Now that we're ready to use the TApp, let's first go through the design of the business logic.

We'll focus on two different users to see the Retweet Task's busines logic: the **task creator** and the **task taker**. These will correspond to two different Metamask accounts. We assume that both accounts have used the faucet to get the initial 1000T in their respective accounts and set the spending limit for the app so they can use it for fund transfer.

### 1. Task Creator Creates the Task

The task creator creates the task by setting these three parameters within the task creation modal window:

1. Tweet url to be quote tweeted.
2. The reward for completing the task.
3. The deposit task taker must put up to take on this task.

![1\_create](https://github.com/tearust/teaproject/assets/86096370/3a91f4ed-63f9-4922-b25b-a66e3f675abe)

### 2. Task Taker Takes the Task

The Task page UI for the Retweet Task TApp has a "take" button as shown below:

![2\_take](https://github.com/tearust/teaproject/assets/86096370/a77ef01c-387d-4663-bba5-7f7b05bc4e7e)

Note that at the time of taking the task, the task taker's balance will decrease by the amount required by the task. If for example the deposit required is 5T, then the task taker's account balance will decrease from 1000 to 995.

![Pasted image 20230317091328.png](/files/DIvJEzj6xnXPLEsrIBn3)

After clicking "take", our **task taker** account is now the worker for this task. Next the task taker has to click **complete** to actually work on the task:

![3\_complete](https://github.com/tearust/teaproject/assets/86096370/e6df40f3-ef0c-485f-836a-5ced3563b29a)

After clicking on **complete**, a new modal will open up:

![4\_retweet](https://github.com/tearust/teaproject/assets/86096370/4579ba32-9802-4ab9-bc09-1d43546b1294)

To complete this task, the user will have to follow the instructions in the modal and complete a **quote tweet** of the original tweet.

Once the task taker has pasted in their quote tweet url in the box, they'll click the **Confirm** button.

At this point the business logic branches according to the response from the Twitter api:

* If the api confirms it's a successful quote tweet, then the task taker gets the bounty as well their initial deposit back.
* If the api returns that the quote tweet isn't of the original tweet, then the task taker's bounty is slashed and is added to the bounty for the task. The task then goes back into the available task queue and is available for anyone to take.

If the quote retweet is confirmed by the Twitter api, the user will get a notice in the upper right corner indicating that the bounty has been deposited to their account:

![5\_success](https://github.com/tearust/teaproject/assets/86096370/10f4a8e1-40e5-453e-abc4-c000d4f43cc1)

Because the user testing their TApp has both accounts in their Metamask, switching between them will show the funds transfer logic. The task taker's deposit as well as the task creator's bounty are held in a virtual escrow account and divvied up according to if the task was completed successfully. Funds transfer can be confirmed by switching between the two accounts.

## TEA Project's Secure Oracle Feature

When we make the call to Twitter to get the api result of the retweet check, we're relying on Twitter to provide an oracle service which gets bridged over to web3 through our nodes. Note that TEA is able to vouchsafe the integrity of the oracle result because of our use of secure hardware. Once the oracle (the Twitter api in this example) reports its result to one of our TEA nodes, the result is stored within the protected enclave of the node. It's completely trustable as nothing can breach the integrity of the enclave, which is why we refer to it as a secure oracle.

The biggest oracle provider in the web3 space is Chainlink and their operating procedure is much different. They instead have their own consensus protocol where multiple Chainlink nodes have to reach a consensus on an oracle result before being able to vouch for its integrity. The TEA Project's use of secure hardware means that we don't have to engage in this wasteful consensus process just to get a trustable oracle result. TEA does run a simpler consensus on its TEA nodes to ensure that their hardware hasn't been tampered with. This is a completely trustable process due to the hardware security modules onboard the TEA nodes. And because TEA's secure enclaves are also the basis of its secure compute layer, conceivably any compute logic output done on the TEA node network is a trustable oracle result avaiable to be consumed by another endpoint.


# Retweet Frontend

There are superficial UI differences when comparing the Retweet Task app to the more general Task app. But we're going to ignore most of them while only focusing on the key changes related to the retweet verification logic.

After the task taker clicks the "complete" button, this is where the new business logic kicks in. It will trigger a secure oracle API call in the backend and verify that this is a successful retweet.

Let's take a look at the front end code trigged by the "complete" button, which is located at `src/layer2/task.js` and specifically inside the `async completeTask` callback section:

```
cb: async (form, close) => {
        self.$root.loading(true);

        let tweet = form.text;
        if(reg_tweet.test(tweet)){
          const arr = tweet.match(reg_tweet);
          tweet = arr[2];
        }

        const opts = {
          address: self.layer1_account.address,
          tappIdB64: base.getTappId(),
          authB64: session_key,
          subject: param.subject,
          text: tweet
        };

        try {
          await txn.txn_request('complete_task', opts);
          await succ_cb();
        } catch (e) {
          console.error(e);
          self.$root.showError(e.toString());
          if(error_cb){
            await error_cb();
          }
        }
        close();
        self.$root.loading(false);

      }
```

This code first takes the tweet url then parses and puts it into the opts. After that it sends a txn request: `await txn.txn_request('complete_task', opts);`.

Right after the txn\_request, it starts to `await succ_cb()`. This makes the front end wait for the successful return from the backend, at which point the waiting ends.

This front end logic is fairly basic and is typical of what a front end is supposed to do. The majority of the main logic happens in the backend.


# Retweet Sample Actor

In this step we'll only focus on the changes related to the secure oracle. Other departures from the general Task TApp are largely superficial as explained before and won't be discussed in this article.

In the sample actor, the handler of `complete_task` will first send a `send_custom_txn` to the state machine with param `complete_task`. This tells the state machine to prepare a secure oracle task.

```
pub async fn complete_task(payload: Vec<u8>, from_actor: String) -> Result<Vec<u8>> {
	let req: CompleteTaskRequest = serde_json::from_slice(&payload)?;
  check_auth(&req.tapp_id_b64, &req.address, &req.auth_b64).await?;
	info!("Complete Task action...");

	let txn = Txns::CompleteTask {
    subject: req.subject.to_string(),
		auth_b64: req.auth_b64.to_string(),
	};

	request::send_custom_txn(
		&from_actor,
		"complete_task",
		&req.uuid,
		tea_sdk::serialize(&req)?,
		tea_sdk::serialize(&txn)?,
		vec![],
		TARGET_ACTOR,
	)
	.await?;

	help::result_ok()
}
```

In the future, the state machine will run a consensus workflow to select a group of hosting or worker nodes to execute this secure oracle task. But in our sample demo, we simplifly "callback" the current hosting node to execute this secure oracle task. This will essentially be a placeholder until the full consensus algorithm is written. Note that consensus here is on the operational environment of the nodes to ensure hardware integrity, not on the result of the secure oracle process.

After the state machine has prepared for the execution of the secure oracle, it will call back to this hosting node with `complete_task_cb` .

```
pub async fn complete_task_cb(payload: Vec<u8>, from_actor: String) -> Result<Vec<u8>> 

```

Inside this function, it will trigger an API call `twitter_request` just as below:

```
	let req: CompleteTaskRequest = tea_sdk::deserialize(&payload)?;
	info!("Complete Task callback action...");

	let pass = oracle::twitter_request(&req.text, &req.subject).await;
```

This is a typical http API call but instead it happens inside the enclave. If you want to know more about how this API call works, you can go to `src/oracle.rs` and look at the function `pub async fn twitter_request`. It looks nothing new outside of what you'd see in a typical twitter APi call. However, it doesn't call a regular HttpRequest as a normal web2 backend would. Let's take a closer look on how it calls the twitter api:

```
  let req = OracleHttpRequest {
    method: "GET".to_string(),
    url,
    headers: Some(headers),
    payload: None
  };
  let rs = ActorId::Static(tappstore_client::NAME).call(
    req,
  ).await?;
  let json: serde_json::Value = serde_json::from_str(&rs.text)?;
  
```

OracleHttpRequest is a struct param that used to trigger a system actor called `client-actor` to actually call the outside twitter server on behalf. Here is a copy of the OracleHttpRequest handler inside client\_actor:

```
impl Handle<OracleHttpRequest> for ActorHandler {
	async fn handle(&self, req: OracleHttpRequest) -> Result<OracleHttpResponse> {
		let method: &'static str = Box::leak(req.method.into_boxed_str());
		let mut builder = request::http::Request::builder()
			.method(method)
			.uri(req.url)
			.body(match req.payload {
				Some(p) => p,
				None => "".to_string(),
			})?;

		if let Some(headers) = req.headers {
			for (key, val) in headers {
				builder.headers_mut().insert(
					request::http::HeaderName::from_str(&key)?,
					request::http::HeaderValue::from_str(&val)?,
				);
			}
		}

		let res = builder.request::<String>().await?;
		let text = res.into_body();
		Ok(OracleHttpResponse { text })
	}
}
```

For security reasons, the user defined actors (such as sample-actor and sample-txn-actor) are not allowed to call an outside http server directly. It can only use OracleHttpRequest and run through the whole oracle algorithm to have someone picked by the state machine to make the request on its behalf. This is how the security design of the TEA Project comes into play.

Using the secure oracle algorithm, neither the developer or the end user can prediect which node or nodes (we call them executors) have been designated to send/receive this http call. Even if a few of the selected executors collude or are otherwise corupted, we can still get the true oracle result as long as the state machine consensus follows the BFT rule. This consensus on the integrity of the TEA node operational environments is a crucial part of the OracleHttpRequest and indirect delegation process.

At the time of this tutorial is written, the executor selection and dispatching algorithms are still under development. We won't be able to elaborate on how they're expected to work at the present moment. As a temporary placeholder, we'll just directly call back the calling hosting node as the executor.

Next up is to handle the http response which we'll tackle much the same as the previous step. We only need to pass in the `pass:bool` from the secure oracle.

```
	let pass = if pass.is_err() {
		false
	} else {
		pass.unwrap()
	};

	let txn = Txns::VerifyTask {
    subject: req.subject.to_string(),
		failed: !pass.clone(),
		auth_b64: req.auth_b64.to_string(),
	};
	info!("Begin to send verify txn => {:?}", txn);
	request::send_custom_txn(
		&from_actor,
		"verify_task",
		&req.uuid,
		tea_sdk::serialize(&req)?,
		tea_sdk::serialize(&txn)?,
		vec![],
		TARGET_ACTOR,
	)
	.await?;

	if pass {
		help::result_ok()
	} else {
		help::result_error("Non-valid retweet. Please check that you've quote retweeted the source tweet and try the task again.".to_string())
	}

}
```

Note that this workflow may change after the secure oracle dispatching algorithm is done. The call back function will become the executor function. It will be called by the state machine maintainer if a hosting node is selected to be an executor. No one can possibly know which node will be selected and no one knows what the final result will be. This is because the final result will be determined by the secure oracle consensus algorithm between the state machine maintainers. However, the basic steps would be the same as they are now and proceed through the following steps:

* The hosting node handles the request from the client.
* Next it generates OracleHttpRequest
* Then it sends theOracleHttpRequest to the state machine maintainers
* The callback (executor) function will be called if the hosting node is selected by the secure oracle consensus (else nothing is called when it hasn't been selected).
* The executor executes the http request logic, and sends the result back to the state machine. Note that the executor may or may not be the original hosting node. There also may be more than one executor depending on the requirements of the secure oracle.
* The state machine runs the secure oracle consensus to determine the final result. Given a variance of responses from the executors, the developer will need to write an algorithm to determine which is the "correct" result.
* The state machine sends the final result back to the calling hosting node.
* The hosting node sends the final result back to the client.


# Retweet Txn Executor

You might be surprised to learn that there's not a lot of code changes in the sample-txn-executor project and that there's almost no changes in the txn executor actor. There's nothing the developer needs to do to execute the secure oracle. Comparing this step with the last step, the newly added business logic all happens inside the hosting node (the sample-actor project). Originally in our previous step, the task owner needed to click a button to confirm the worker successfully completed the task. In our current retweet project, this "confirmation" is done by the secure oracle automatically. The secure oracle will call the twiter API to verify if the worker has actually successfully retweeted the original tweet.

All of the secure oracle workflow is transparent to the developers. You as a developer only need to create an OracleHttpRequest and call. In our future developer documentation, there will be more OracleSomethingRequest published. We'll open the code base so that you can write your own OracleYourselfRequest to run different oracles. Furthermore, your actor can earn TEA tokens for you if someone calls your actor. Our billing system will measure the usage, and the caller will pay you. Note that your code (your actor) is an NFT, and you're the owner of this NFT. Your NFT works for you and makes you profit. Isn't that amazing?


# Retweet FAQ

!!!George: Please write on your own in this article, try to cover my following questions!!!

## Busienss ideas

As a developer, what are the potential opportunities of using secure oracle

## Why do we need secure oracle to call API instead?

Compare with web2 directly function call, what are the benefits of secure oracle, why do we need security oracle to call API, what if we call directly, any problems?

## Do I need to pay to use secure oracle?

Billing related to secure oracle. George, you can asnwer like this: The developer of the secure oracle actor may have their own pricing model. TEA Project will help billing. If you as an app developer decide to use any existing secure oracle function, you will need to understand and agree on its pricing model. In the runtime the TEA Project will measure the usage and enforce the payment.

## How do I make money by providing a secure oracle as a developer

Note, this feature is not completed at the time of writing.

If you write a seure oracle actor and published to the TEA Project, you are the owner of this NFT. All actors are NFT in TEA Project. You can also publish your pricing policy that follow the TEA Project billing rules. If some other application calls your secure oracle, the TEA billing system will measure and enforce the payment from the caller. So you can learn the passive income by providing such secure oracle actor. Please note, this is NOT gas fee. It is just the actor usage fee or in-app purchase. Gas fee is computing resource cost pay to the miners.


# Gas Fees

Tokenomics (Token-Economics) is an important design consideration to incentivize desirable behavior in a decentralized ecosystem by rewarding participants who provide useful services. The TEA Project has a carefully designed tokenomics. The following tutorial will cover some basic concepts of the TEA Project's carefully designed tokenomics. For full details, please see the tokenomics section of our white paper.

## Gas fee

When endusers want to use a TApp, that TApp is hosted by a decentralized "miner" in our TEA network. Because this miner is providing their hardware for the enduser's use, the miner should be paid for providing their machine and rewarded for their service. This is where the **gas fee** comes into play, namely the enduser pays a gas fee to the miner for the computing hardware service they provide. The gas fee is calculated according to how much resources are used on the miner's host machine.

In the TEA Project's wasm runtime, we have a billing system that measures the CPU instruction when the CPU is executing the wasm actor code. The result of this measurement is summed up every few minutes. We currently set an exchange rate of 10M CPU units to 1 TEA. This exchange rate may change in the future as directed by the TEA DAO. At this moment, we can assume that it's a constant value, and that **the TEA's value is anchored to the computing consumption**.

In this tutorial step, you'll see a new log page which includes the gas payment log.

![Pasted image 20230321092915.png](/files/vELtkAGEIlxc9XEMnYXt)

As you can see from the screenshot, most regular operations will cost between 0.00001 to 0.001 TEA. For some complicated computations, it may be as large as 0.1 TEA but this would be very rare. As a developer, you should always run the local testing in dev-runner and monitor this log page to get an estimate on how much gas your code may consume. There are many ways to optimize your code to consume less gas. Most rules developers used for Solidity (Ethereum) would apply to the TEA Project as well.

## Build and run

Assuming you're in the `reward` branch and continuing from our last tutorial, stop the docker container as well as npm by typing Ctrl C seperately in their respective terminal windows. We'll need to clear the stored state before moving on to the new branch.

In the `dev-runner` terminal window run `rm -rf .tokenstate` to clear the stored state. Once you've cleared the old state, when you start `docker compose up` next time, you'll need to reinitialize the token and database. This is an easily forgotten step so we want to emphasize it and will remind the reader later in the tutorial.

In the `tutorial-v1` terminal window, switch to new gas branch by running the following command: `git checkout gas`.

Run `./build.sh` specifically in the `sample-actor` and `sample-txn-executor` folders. Verify the two actor wasm files are newly built in `dev-runner/local/a-actor` and `dev-runner/local/b-actor`.

Now we can start the dev-runner by issuing `docker compose up`, then in `tutorial-v1/sample-front-end` run `npm install` and `npm start`. Nest go to the <http://localhost:3200/> url in your browser.

## Test locally

Do not rush to login yet. Click the "Click here to send request" button in the Help page first. You should see an alert of Hello World. If not, the backend docker has not completed loading yet. Just wait another few minutes and try again.

Because you've deleted `.tokenstate`, this is a brand new environment. You'll need to go to the Admin page and click the two buttons: Initialize token and Initalize database. Otherwise, all other operations will fail.

Now you can login. Then make sure you click "Faucet" to get 1000 test TEA. Otherwise, you won't have enough funds to run any operations or pay any gas fees.

You can run some test tasks as you did in last tutorial step. This is a helpful exercise as a way to consume some gas so such that it'll show up in the log after a few minutes.

Assuming you have done some operations such as creating a task or taking a task, you should be able to see a record of your actions in the Log page after a few minutes. The records will show your consumption and how much you paid for the gas fee.

Note that in the log page, you'll see all TEA transactions including gas fees as well as in-app purchases and fund transfers.


# Query logs

In this `gas` branch, there's only one major change and it's in the **sample-actor** project. The **sample-txn-executor** has no change because it has nothing to do with gas fee logs. The sample-front-end added a new UI but mainly it's just typical VUE web UI code changes, so there's no need to explain it in our tutorial. So let's only focus on the **sample-actor** project.

We'll need to add a new query to get the list of logs and a txn to set the allowance. You can find them in the `dfn.rs` file:

```
pub fn name_list() -> Vec<&'static str> {
	vec![
		"say-hello",
		"faucet",
		"create_task",
		"query_task_list",
		"delete_task",
		"verify_task",
		"take_task",
		"complete_task",
		"init_db",
		"init_token",
		"queryOpLogs",//this is the newly added function
		"setAllowance",
	]
}
```

These are called "queryOpLogs" and 'setAllownace' which you can see at the end of the file. The txn to `setAllowance` is related to the fact that each TApp has an allowance associated with it. The TApp will only be able to spend user funds up to the amount set as the allowance.

In **api.rs** you can find the `async fn query_op_logs` function. The major logic is to call the `get_statements_async` function.

```
	let (statements, read_to_end) = get_statements_async(
		acct,
		date,
		IntelliSendMode::RemoteOnly,
	)
	.await?;
```

then convert the rows to human readable format:

```
	let mut rows: Vec<JsonStatement> = Vec::new();
	for item in statements {
		let s = item.0;
		let tmp = JsonStatement {
			account: format!("{:?}", s.statement.account),
			gross_amount: s.statement.gross_amount.to_string(),
			statement_type: s.statement.statement_type.to_string(),
			token_id: s.statement.token_id.to_hex(),
			state_type: s.state_type.to_string(),
			memo: item.2,
			time: item.1,
		};
		rows.push(tmp);
	}
```

In our runtime, we store records in the log based on date. So we'll query the backend on which dates to query.

```
	let date: Option<SimpleDate> = req
		.year
		.as_ref()
		.map(|year| SimpleDate::new(*year, req.month.unwrap_or(1_u32), req.day.unwrap_or(1_u32)));
```

Once we've received the json response, the calback function formats them to a UI-friendly format. After that, `help::cache_json_with_uuid(&uuid, x).await?;` caches it to local memory and waits for the front end to check this result at a later time.

The code above shows a typical example of how to convert the data from the backend to the web UI friendly format. In this tutorial we cover it for TApp development but it's the same formatting that's commonly used everywhere.


# A deep dive into gas measurement and settlement

## How is the gas fee measured for my TApp?

As a TApp developer, you're writing wasm actor code. Your code will be compiled into a wasm binary file and then loaded into the TEA runtime to execute. The TEA runtime is based on [wasmer](https://wasmer.io/) which can measure computing consumption during code execution.

## How is gas fee measured or estimated for Native Actor Functions?

Your code may call other functions provided by the tea-sdk. Most of those functions are **Native actor functions**. They're not wasm code but native code. There's no way for wasmer to measure the gas fee of native code. So the TEA runtime will give every native function an "estimate price" based on calibration. We'll release a price list when the TEA Project launches into production release.

Your input arguments for the native function call may significantly affect the gas consumption, so there's an **estimate** function for every native function. This estimate will be used for every native call before actual execution. In case the estimate is over the gas limit, the function will not be executed, and will return a "gas limit overflow" error.

## What is the gas limit, and what happens if it's exceeded?

The gas limit is borrowed from Ethereum. It's used to protect the consumer in case of any unforeseeable situations (software bugs such as an infinite loop, garbage input data etc. ) which causes an extremely huge gas bill. It's also used to prevent DDoS attacks.

All operations will carry a gas limit with the function call. The gas consumption is measured and deducted in real time. As soon as the gas limit runs out, the execution will be terminated immediately. The caller will receive an error of Over Gas Limit.

Because the native function call cannot be terminiated during execution, an estimation function will be called before execution. If the gas limit cannot cover that estimation, the execution will be terminated before actually called.

During our test phase, we set a 1 TEA gas limit for all operations which should be large enough. In the future, we'll allow developers or end-users to set their own gas limits for any specific operations that consumes a lot of gas.

## When is the gas settlement?

Although the gas limit is measured and deducted in real time, the payment of the gas fee from the end users to the miners is not settled in real time to reduce the system load. The bill will be accumulated and settled after a period of time. This time is called the Billing cycle.

In our local dev-runner, it's set to one minute just so that we can get the gas bill logged sooner. In our testnet, it's set to 10 minutes. Likely we'll set a 10 minute billing cycle in our production envrionment, but it may change in the future.

There's a chance that the payer cannot pay the gas bill in full at the time of settlement. This is considered bad debt which is unavoidable and in most cases acceptable. We'll measure the bad debt ratio in our future production environment. Based on that ratio, we may decide to increase or decrease the gas limit restriction. It's always a trade off between bad debt and cost of the system load.

## Other costs or profits from developers point of view

The gas fee is paid by the enduser to the miners. For developers there are other profits or costs:

* Memory tax: Paid to the state machine for occupying memory in the state (or SQL).
* Txn fee to the state machine: Paid to the state machine for executing the txn-executor.
* Gas subsidy for end users: Developer can cover the gas fee originally payable by the end user, e.g. a developer could subsidize gas to promote usage of their app. Thus the end user can use the TApp for free.
* In-app purchase: End user pays the developer (the TApp). This is the direct income to the TApp.

For more detail, please go to the tokenomics section of the TEA Project's white paper.

## Reduce the gas fee and memory tax

If you know how to reduce the gas cost in Ethereum, all those rules will also mostly work in the TEA Project. Additionally, you should also consider how to reduce the memory tax, which doesn't existing in Ethereum. The details of the Memory Tax is beyond the scope of this tutorial. We can list a few items to consider but more details will be covered in our developer documents and in our future Tutorial-v2.

* Delete records in SQL instead of simply "mark-as-deleted". SQL data lives inside the memory of all state machine enclaves. Memory is an expensive resource.
* Only store relationships to SQL and store all blob data to OrbitDB. The blob storage is beyond the scope of this tutorial. We'll cover it more in our tutorial-v2.
* When possible, store the query result locally using the Native actor's "keyvalue pair provider". This is a cache that can significantly reduce queries to the database. In our future version, a local state cache can allow you to almost exclusively perform local queries.
* When possible, combine smaller txns into one larger txn.
* If there's a native actor function that can do something, never rewrite your own wasm version. Wasm code is always more expensive than Native code.
* If you know of another developer's actor that's widely used for some feature, please call them instead of rewriting your own. In most cases, those widely used popular actors are optmized to save costs compared to your newly written one.
* Run your code locally using dev-runner and check the log to see how much gas it consumes. This "dry run" can save you and your customers a lot of money before testing in the real production environment.


# Summary

## Three parts of a typical TApp

We have gone through the entire process of building a TApp. The development contains three major projects.

* Front end.
* Hosting actor, also known as back end in the web2 world.
* Txn executor, also known as stored procedure in the web2 world.

The Front end is a SPA(Single page application).

* It runs in the browser (or as a mobile-style client in mobile devices).
* Its final built code is stored on IPFS. The CID will be the key for end users to access the TApp.
* It sends HTTP POST requests to the backend (hosting actor), and waits for responses.
* It uses Metamask to identify the user. Whoever can sign the login string will be recognized as the authorized user.

The Hosting actor runs inside the hosting node.

* It's compiled to a wasm file and loaded into a hosting node.
* All logic in the wasm code are Lambda functions. It takes requests and returns responses.
* It sends queries or transactions to the Txn executor actor in the state machine whenever there's a query or request to change the state, respectively. In our future version, a local state cache will be added to speed up the local query.
* Because all functions are Lambda, they're purely functional and don't store the state unless they call the TEA Project native providers to do so on their behalf. Always assume the local state is vulnerable to be wiped as the hosting node may finish or restart at any time.
* All function execution needs gas as fuel. The miner who runs the hosting node gets paid by the paid gas fuel. More details on the gas fee can be found in the Tokenomics section of our white paper.

The txn executor actor runs inside of every state machine node.

* It's compiled to a wasm file and loaded into every state machine maintainer.
* All logic in the wasm file are Lambda functions. It takes txn parameters, and returns the result or modifies the state.
* All logic needs to be **deterministic**. No randomness or any I/O that may cause exceptions is allowed.
* The txn executor can call a limited list of native providers.
* The txn executor writes all state changes to the Context `ctx` object. At minimum, it'll return the list of Contexts. The TEA Runtime will commit the changes to the state.
* At any point of execution, when any error happens, the txn executor will return the error without commiting any state changes (i.e. the state will remain the same).
* The TEA runtime will sort all incoming txns based on their timestamps. So that all state machine maintainer nodes will execute on the same sequences. This is the Proof of Time consensus we discussed in the white paper.

## Local development and local test

You're not supposed to run a prototype in the production environment because you're risking real money. Deploying on testnet won't need real money, but it takes some time and has a longer feedback loop. So the best way to test your business logic would be to run it locally.

Like Hardhat for Ethereum development, we have Dev-Runner to use as a local simulator. There are still a few differences between the production and local Dev-Runner. For example, you may have an additional admin page to trigger the initiliazation step. This step is part of the Developer Portal in the production environment. Also, you can use a **faucet** to get free test tokens, which isn't possible in the production environment.

## Deployment

TODO://

## Gas fee

TODO://![Pasted image 20230320085836.png](/files/7bNVeMVAKG3QKr3pBJW5)

## What's next

There are many simplification or placeholders in our tutorial-v1, such as:

* The developer has not get paid yet.
* The task title is a unique value. If someone created "Buy me a beer", no one else can create a task with the same title later.
* The creator needs to be honest when verifying the worker's work. We would need a "secure oracle" to determine if the task is completed successfully without relying on creator's honesty.
* There's no time limit. The worker can take a task and never complete it.


# Billing


# Billing FAQ

## How can developers reduce the gas that their apps require?

* Optimize code. Developers can use the same coding techniques that work to [reduce gas fees on Ethereum](https://www.alchemy.com/overviews/solidity-gas-optimization). We also have a [local test environment](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/030_billing/t-rust/obsidian/_gitbook-dev-docs/030_billing/local-debug-environment.md) that developers can deploy to get an idea of how much memory / memory cost their actors are consuming.
* Optimize state machine memory usage. Since TApps pay a memory tax, devs can reduce the cost of running their apps by using the least amount of state memory as possible. This fee is a memory tax  separate from the gas fee. Developers might wonder if they're charged gas for the amount of cache memory utilized within CML hosting nodes. While there's a hosting actor within the hosting node that TApp's can cache memory to, the TEA Project doesn't charge for this memory usage as it's only temporary. Besides that, it's also hard to measure.
* Choose optimal native function routing. Native function calls have different gas prices associated with them. If the call stack has optional native functions, then devs can play with the gas estimates to see which routes provide them with the cheapest overall gas costs.
* Leverage different possible hardware options through function calls. A powerful GPU can potentially do in 1 line of code what a CPU takes 10,000 lines of code to perform. But if the GPU function call is only 10x more expensive, then that line of code executes at a fraction of the gas cost compared to calling the CPU. Only native functions can access hardware directly, so devs will need to use the gas estimator to find the most efficient path that leverages the CML host's hardware.

## Why is there a gas limit?

There's a default gas limit in place on TApp operations as a safeguard against code execution running up an exorbitant fee and bankrupting the enduser.

The gas limit is set at a default value by the TEA Project and technically applies to each actor of the currently running TApp. The gas limit acts as sensible protection against edge cases where actors begin using a large amount of memory. The gas limit is a soft limit and is the max that the end-user will pay to the miner in order to run that particular TApp's actor. Note that gas fees are paid by the end-user and go to the CML miners up to the point of the gas limit. Once past the gas limit, the responsibility for paying the miners falls on the TApp developer who has a security deposit for such cases.&#x20;

In addition to the gas limit, the TEA Project has a **fuse** which acts as an emergency break point for any of the actors. This further protection beyond the gas limit is necessary in some cases of recursion. For example, an infinite loop that continues to rack up gas charges without ever completing will have to eventually break when it hits the fuse. More about the gas limit and fuses is covered in a [separate document](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/030_billing/t-rust/obsidian/_gitbook-dev-docs/030_billing/gas-fee-billing.md).

## Why do TApps need to pay a memory tax?

The state machine's memory is a scarce resource. It's a resource that's shared by all TApps and as one group of TApps uses more of it, that means there's less of it available for the other TApps. In order to encourage conservative usage, a memory tax is billed to the TApp based on how much memory it uses and how long it occupies space in the state machine.

Note that the Memory tax rate is not linear: as the state memory utilization increases and the remaining available memory becomes scarce, the memory tax starts to climb. The higher memory tax rate during high utilization periods will compel some applications to reduce / optimize their memory usage.


# Gas Fee Billing

It should be noted at the outset that the TEA Project’s billing and settlements happen at different times. The billing record is kept in real time while the settlement of the billing cycle occurs every \~ 5 minutes (subject to change).

Let’s first focus on how payments are routed for the gas fee. In graphical form:

![Gas Fee (in depth)](https://user-images.githubusercontent.com/86096370/218186875-93b7aaa8-3194-4a43-8f1b-8572e77dec04.png)

1. The end-user’s gas payment to miners actually goes to an accrued account.
2. (Optional) A system expense that some CML pay to receive faster state updates is the **state subscription fee.** If the miner has a state subscription, then the system will pull from the accrued balance whenever this fee is due. If there’s no funds in the accrued balance when the fee is due, then some of the CML’s bonding curve tokens will be liquidated to pay for the charge.
3. If there’s funds in the accrued balance, then at regular intervals (currently anywhere between 5–20 minutes) they will be swept and paid out as dividends to CML bonding curve token holders.

More information is available in our [billing-faq](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/030_billing/t-rust/obsidian/_gitbook-dev-docs/030_billing/billing-faq.md).


# Gas & Fuse Limits

The TEA Project uses a **fuse** design to ensure that developer's code doesn't use more gas than expected (e.g. infinite loops, recursion).

In the TEA Project design, there's a soft limit known as the **gas limit** in addition to a hard limit where the **fuse** kicks in.&#x20;

* The end-user has a gas limit which they acknowledge they're responsible for when using the TApp.
* The developer has a security deposit that's charged whenever an actor uses more than the gas limit up until the fuse point where their entire security deposit is slashed.

Each actor has its own security deposit that the developer must fund. These security deposits correlate to the memory quota of the actor which is the max amount of memory that actor can use. This memory quota is set by the TEA Project and is the same for each actor. The larger the memory quota, the higher the security deposit.

The fuse limit sits above the gas limit and is also set by the TEA Project.

The following table summarizes what happens when these two levels, gas limit and fuse, are breached.

| Exit Stage                                                     | Exit Status                                                                         | Payment Responsibility                                                                     |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Up to & including the **gas limit**.                           | Actor exits normally, memory is released.                                           | End-user pays for any gas amount up to the gas limit.                                      |
| Exceeded **gas limit** but not yet reached the **fuse** level. | Actor exits normally, memory is released.                                           | Developer pays for any gas amount above the gas limit, which is paid to the hosting miner. |
| **Fuse** is tripped.                                           | Actor is terminated by the mini runtime, and memory is set to be garbage collected. | Dev deposit is slashed completely when fuse is tripped and is paid to the hosting miner.   |

The developer can run their code in a [test environment](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/030_billing/t-rust/obsidian/_gitbook-dev-docs/030_billing/local-debug-environment.md) to get an idea of each actor’s memory usage as well as test for edge cases which cause high utilization.


# Local Debugging Environment

TEA App developers can launch their own local debug environment through Docker. This local development environment has the following features:

* The debug environment comes as a self-contained Docker image that’s deployed to local machine.
* Single state machine node, single hosting node. Because these are only single nodes, there's no consensus for txns and no security. The developer also doesn't need to pay the memory tax or pay to use the hosting node.
* Full billing system support.
* Uses manifest to load actors.

These features of the local testing environment help developers estimate how much memory their app's actors will use as well as the gas cost. Because the manifest is used to load actors, there's no need to create a TApp first which saves the developer time.


# State Maintainer Billing

The [TApp billing](/030_billing/tapp-billing) shows the revenue side for the state maintainer nodes, namely the txn fees and memory tax. To show a complete picture of the profitably of being a state maintainer we should also describe the associated expenses of running a state maintainer node.

The following graphic describes the state maintainer revenue and expenses and their destinations:

![State Maintainer Billing](https://user-images.githubusercontent.com/86096370/218186861-63a9d980-dafa-45cf-96f5-6a015d942353.png)

1. The state maintainers pay a **Harberger Tax** on their self-assessed value to a **temp treasury fund**.
2. The temp treasury fund sweeps these funds at regular intervals to the public service rewards due to the CML nodes for performing public services like remote attestation.
3. Surpluses above what’s needed to pay for the public service rewards are remitted to the TEA DAO.

Readers interested in learning more about the structure of state machine payments can consult the following article: [Efficient State Machine Usage Through Taxation](https://teaproject.medium.com/proposal-efficient-state-machine-usage-through-taxation-2010ab1b294f).


# TApp Billing

The calculus for a TApp that must pay for the txn fee and memory tax is a bit different depending on what rate it charges for TApp usage.

* If the TApp usage fee charged covers the txn fee and memory tax, then the excess is paid as a dividend profit to the TApp’s bonding curve token holders.
* If conversely the usage fee charged isn’t enough to cover the state machine related costs, then the TApp will be losing money every time an end-user uses the app. This could especially be the case with not-for-profit TApps that don’t charge a usage fee.

Visually the revenue and expenses for the TApp portion of the end-user’s payment looks like this:

![TApp Billing](https://user-images.githubusercontent.com/86096370/218186872-384f76cf-4695-4b0f-b9b4-7c5c484f162c.png)

1. The TApp charges a usage fee taken from the end-user’s payment that goes into the accrued balance account.
2. The txn fee and memory tax owed by the TApp draws from the accrued balance into the **collection pool**.
3. The collection pool is settled at regular intervals (5–20 minutes) into the wallets of the state maintainers who receive the txn fees and memory tax as revenue.
4. Settlement from the accrued balance goes into the TApp’s bonding curve at regular intervals of between 5–20 minutes. Because this happens post-expenses, this accrued pool could either be positive (resulting in a dividend distribution as shown in the graphic) or negative. If the accrued balance is negative net of the txn fees and memory tax, then that shortfall is levied as an expense to the TApp’s bonding curve token holders.

This latter scenario is exactly the reverse of what happens when TApp usage generates a profit. Instead of new TApp tokens being generated and sent to existing TApp token holders as a dividend, TApp tokens are taken from the existing token holders and liquidated for their TEA value to pay the necessary state machine expense. This would eventually lead to the bonding curve token being liquidated.

These actions — dividend payouts for profits and token dissolution for expenses — occur at regular settlement intervals. Because the bonding curve can remove tokens from among its holders, TApp token investors should perform due diligence on the TApp to ensure expenses are covered by the TApp usage fee. A TApp token is just like any other investment that has risks, and dividend payouts along with token subtractions are part of the nature of the bonding curve.

More information is available in our [billing-faq](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/030_billing/t-rust/obsidian/_gitbook-dev-docs/030_billing/billing-faq.md).


# Example TApps


# Advanced TApps


# TEA Party TApp Intro

## The goal of TEA Party

We built the TEA Party TApp to show:

* What a typical [web3](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/045_advanced_tapps/t-rust/obsidian/_gitbook-dev-docs/010_core_docs/070_What_makes_a_Web3_application.md) looks like (we call them **TApps**).
* The building blocks of a typical TApp.
* How to use Tea Party as a boilerplate to build your own TApps.

The TEA Party TApp is a useful social media application. Users can post messages to a public board as well as send private messages with notifications. See [the TEA Party user guide](https://teaproject.medium.com/tea-party-tapp-epoch-9-users-guide-2bd8ddd87daa) for more information.

## Basic workflow

In this section, we'll learn the basic workflow between all three tiers: how a user action get processed from the front-end to the state machine layer and back to the user.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>A: click the Tea party URL received from shared link or wallet
rect rgb(222,222,222)
A->>+B: reqeust to launch the Tea Party via the url link
B->>+C: get the CID and request IPFS
C->>-B: resposne the html/css/js front end code
B->>-A: send back the html/css/js front end code
A->>A: render on the browser. show the UI to the end user.
end
rect rgb(222,222,222)
A->>+B: query the NoSQL data (such as messages list without querying SQL database)
B->>+C: query OrbitDB
C->>-B: response data (such as message body)
B->>-A: send message body
A->>A: render in browser, showing to the end user
end
rect rgb(222,222,222)
A->>+B: query SQL database (such as my starred message list)
B->>+D: sending query txn
D->>+F: dispatch query txn
F->>+H: actor query GlueSQL
H->>-F: response query result (such as my starred message IDs)
F->>-D: response ids
D->>-B: response ids
B->>+C: query the messages body based on message IDs from GlueSQL
C->>-B: response message bodies that I starred
B->>-A: response message bodies that I starred
A->>A: render on browser.
end
rect rgb(222,222,222)
A->>+B: post a new message
B->>B: generate a command txn to pay for the fee
B->>D: send the command txn and followup to at least two state machine replicas
D->>E: the command txn waiting on all the conveyors
E->>E: waiting in conveyor
E->>+F: after the grace period, the command txn dispatch to state machine actor for execution
F->>+G: actor execute command and call state update
G->>G: update state inside state machine
G->>-F: command txn committed and state changed
F->>-E: response back
E->>D: response back
D->>B: response back to hosting CML
B->>B: confirm the payment went through, now generate post message txn to OrbitDB
B->>+C: insert new message to OrbitDB
C->>-B: inserted
B->>-A: confirmed posting message completed
A->>A: render the UI and notify end user.
end" %}

## The magical Proof of Time state machine

In this section, we'll explain how the distributed state machine works, including how it handles consensus among different replicas. Keep reading about the [magic of the state machine](/basic-concepts/080_magic_of_state_machine).

## Understanding the WebAssembly Runtime

You can learn more about how the WebAssembly code runs inside the [mini-runtime](/z_glossary/mini-runtime) by reading about the [magic\_of\_wasm](/z_glossary/magic_of_wasm).


# TEA Party Code Walkthrough

In this section, we'll walk through the TEA Party application's sample code.

The steps are:

* Clone the code to local.
* Install the build tools.
* Understand the folder structure.
* Understand the compile workflow.
* Run it.

## Code location and structure

Start by cloneing the following GitHub repo to your local machine: <https://github.com/tearust/tapp-sample-teaparty>

There are 4 folders (click the following links for more details):

* [party-fe](/z_glossary/party-fe): This is the [front\_end](/z_glossary/front_end).
* [party-actor](/z_glossary/party-actor): This is the [back\_end\_actor](/z_glossary/back_end_actor).
* party-share: This is the common data structure or library that shared by both the [back\_end\_actor](/z_glossary/back_end_actor) and the [state\_machine\_actor](/z_glossary/state_machine_actor).
* [party-state-actor](/z_glossary/party-state-actor): This is the [state\_machine\_actor](/z_glossary/state_machine_actor).

## Workflow

### Load the UI

Any user can launch a TApp by clicking on one of the [hosting\_cml](/z_glossary/hosting_cml)s urls (there's no domain used when launching TApps). Picking any of the urls will work exactly the same so you can choose the one with least network latency. The URL is nothing but an IPFS CID.

Note: This is a brief diagram. The real communication is more complicated than this.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>+B: http request to load ipfs cid
B->>-C: ipfs load cid
C->>+B: the html/css/js code that the request cid refers to
B->>-A: response html/css/js front end code
A->>A: render the browser. show the UI
" %}

### Query the state

Accounting information is stored in the state (e.g. when querying the balance of a user's TApp account.)

Querying the state can return the result without having to wait in conveyor queue. But the communication is still async, so additional queries for more results are still needed which is not shown in the diagram. You can see the details on additional queries at [party-fe > Workflow](/z_glossary/party-fe).

Note: This is a brief diagram. The real communication is more complicated than this.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>B: http request to query account balance of a user
B->>D: send query to at least two State Machine Replicas
D->>+F: queries do not require conveyor wait, it can query state immediately
F->>+G: actor query state
G->>-F: state response to actor
F->>-D: send back the account balance response
D->>B: send back the account balance response
B->>A: send back the account balance response
A->>A: render the browser. show the account balance on the UI
" %}

### Send a command that changes the state

Commands are more complicated in that certain precautions must be taken before they're allowed to change the state. Like any other distributed state machine, we have to make sure the state in all the [state\_machine\_replica](/z_glossary/state_machine_replica)s are consistent. We use the [conveyor](/z_glossary/conveyor) algorithm to sort the commands by their timestamp and are executed in identical order across all replicas.

The following diagram demonstrates the workflow of how a simple transfer txn command is handled. Note that this diagram is a simplifed verison. The full version can be found here: [party-fe > Workflow](/z_glossary/party-fe).

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>B: http request to transfer fund . (eg. Alice send 10T to Bob)
B->>B: genreate the transfer txn command in back end actor
B->>D: send command to at least two State Machine Replicas
D->>E: put the command txn on the conveyor
E->>E: re-order all txns in the queue during the grace period
E->>+F: time is up. the command is sent to state machine actor to execute
F->>+G: state machine actor execute the txn and update the state
G->>-F: state commited successful. response ok
F->>-D: response ok
D->>B: response ok
B->>A: response ok
" %}

### Running SQL queries

Running SQL queries is almost the same as running a query against the state. The only difference is that we replace the state with the GlueSQL instance. Note: SQL queries are not allowed to change the state. Only `Select` statements are allowed in SQL queries.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>B: http request to query something that stored in SQL database
B->>B: generate SQL scripts

```
B->>D: send SQL scripts to at least two State Machine Replicas
D->>+F: queries do not require conveyor wait, it can execute in state machine actor that query GlueSQL immediately
F->>+H: run SQL scripts in GlueSQL instance.
H->>-F: response query result
F->>-D: send back the query result
D->>B: send back the query result
B->>A: send back the query result
A->>A: render the browser. show the result on UI
" %}
```

### Send SQL scripts to change SQL database

Rather than `select`, many SQL statements will change the database. They are all considered **commands**. The workflow is almost the same as the state command, with the state being replaced by the GlueSQL instance.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>B: http request to transfer a NFT . (eg. Alice send a CML to Bob)
B->>B: genreate the transfer SQL scripts in back end actor
B->>D: send command to at least two State Machine Replicas
D->>E: put the command txn on the conveyor
E->>E: re-order all txns in the queue during the grace period
E->>+F: time is up. the command is sent to state machine actor to execute
F->>+H: state machine actor execute the txn and update the GlueSQL database
H->>-F: GlueSQL commited successful. response ok
F->>-D: response ok
D->>B: response ok
B->>A: response ok
" %}

### Load / save NoSQL data with OrbitDB

Because the state and GlueSQL are memory based distributed databases, they're very expensive when used to store large amounts of data. TApps needing to store large amounts of data should use either OrbitDB (structured data) or IPFS (blob data/ files).

OrbitDB and IPFS live inside the [hosting\_cml](/z_glossary/hosting_cml), so the [state\_machine\_replica](/z_glossary/state_machine_replica)s are not involved in this workflow.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>B: Load the messages list in TEA Party
B->>C: load messages from OrbitDB!\[\[bob-digest.json]]
C->>B: respones the list of messages body
B->>A: messages body list!\[\[bob-digest 1.json]]
A->>A: show the message content on the UI" %}

### Combination of SQL and NoSQL

The diagram above shows a common use case that loads all messages. But in many cases, the ids (index) of the OrbitDB is stored in GlueSQL, so it's very common to first have to query GlueSQL to get the IDs. After successfully querying GlueSqL for the IDs, then we can query OrbitDB using the IDs to retrieve the actual data.

{% @mermaid/diagram content="sequenceDiagram
participant A as Front end
participant B as Back end
participant C as IPFS/OrbitDB
participant D as State machine receiver
participant E as State machine conveyor
participant F as State machine actor
participant G as State
participant H as GlueSQL
A->>B: Load the messages list that I have starred in TEA Party
B->>B: generate a SQL scripts that query for all message IDs that I starred in the GlueSQL
B->>D: Send query txn.
D->>F: queries do not need conveyor, it go to state machine actor to execute immediately
F->>H: run the SQL scripts for IDs of messages that I starred
H->>F: response the message IDs
F->>D: response the message IDs
D->>B: response the message IDs
B->>C: load messages from OrbitDB using the IDs just received from GlueSQL
C->>B: respones the list of messages body that I starred
B->>A: messages body list that I starred
A->>A: show the message content on the UI. all of them are messages that I starred" %}

The above diagram shows the combination of SQL and NoSQL.

## More details on each of the three parts

Click on any of the following links for more details:

* Code walkthrough for [party-fe](/z_glossary/party-fe).
* Code walkthrough for [party-actor](/z_glossary/party-actor).
* Code walkthrough for [party-state-actor](/z_glossary/party-state-actor).

## Run it

TODO:


# Functions


# Actors vs Functions

An **actor** is a compiled file in Wasm binary format that is composed of functions. The actor is loaded into the TEA min-runtime which processes the actor's request and generates a response back to the actor's handler function.&#x20;

TEA's **functions** are like a server-less version of [lambda functions](https://en.wikipedia.org/wiki/Lambda_calculus). Functions are stateless, i.e. developers can't store any state inside the functions.

If a developer needs to store the state while running a function, they have two choices:

1. They can store it in the state machine and pay the associated memory tax. If the data is important (such as token balances), then the data should be stored in a database, i.e. the state machine.
2. Wasm functions can't store the state, but they can call native functions to store the state temporarily through the hosting actor. As mentioned earlier, there's no charge for this kind of state storage because it's only temporary.


# Function Calls Between Native & Wasm

## Call vs Post

There are two ways to call another function from either Native and Wasm functions.

* **Call**: Sync call. The caller will wait for the subroutine to complete and return before continuing.
* **Post**: Async call. The caller will not wait for the subroutine to complete, i.e. the subroutine will run separately from the caller.

## Native function gas estimate function in Tea-Codec

Every native function will have a gas-estimate helper function that stays inside the Tea-codec. This function will run logic to estimate how much gas the function run will cost. Although there's no way to precisely measure the cost, this function will be used to get the best estimate.&#x20;

When a caller calls/posts another function, the calling activity is measured as **estimated cost deducted from gas limit At time of call**. The system will run the **Gas Estimate** function first. If the caller cannot afford this cost (exceeds the gas limit), the function call will fail with error "Gas limit ran out". If the gas limit can cover the cost, the estimated gas cost will immediately be deducted from the calling function's gas limit. This will guarantee that the bill can get paid at the time of settlement.

## How gas is measured in Native/Wasm <> Call/Post combinations

| Call Type          | How Gas is Charged                                                                                                                         |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Native call Native | Free of charge.                                                                                                                            |
| Native call Wasm   | Forbidden.                                                                                                                                 |
| Native post Native | Free of charge.                                                                                                                            |
| Native post Wasm   | Native runs gas estimate function to estimate gas cost it must budget for. This gas budget is then reduced from gas limit at time of call. |

A Native call or post to Native is free because Native can't run the estimate function. Even if it could estimate the gas cost, it wouldn't being able to alter the gas limit of the Native function calling it.

| Call Type        | How Gas is Charged                                                                                                                         |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Wasm call Native | Estimated cost deducted from gas limit at the time call starts.                                                                            |
| Wasm call Wasm   | Measured by Wasmer as real time usage.                                                                                                     |
| Wasm post Native | Estimated cost deducted from gas limit at the time call starts.                                                                            |
| Wasm post Wasm   | Native runs gas estimate function to estimate gas cost it must budget for. This gas budget is then reduced from gas limit at time of call. |


# Native vs Wasm Functions

TEA Project function calls can be either Wasm functions or native functions.

* Wasm actors can be written by developers to run in both the hosting CML nodes and the state machine nodes. Developers will need to write two functions: one for the CML hosting nodes to handle the end-user requests and another for the state machine to handle the txn requests coming from the hosting nodes. The billing costs to run Wasm actors can be calculated exactly which means CML hosts will be paid precisely according to the resources that the function uses.
* An app can call native functions to communicate with the underlying TEA system. Native actors can run in either CML or state maintainer nodes and pay out to either entity accordingly.

## Native functions

* System-level functions.
* Can only be written by TEA Core Team.
* Executed as operating system native code running on bare metal (not virtualization). Code is run directly in the CPU after being compiled into CPU instructions specific for AMD64, ARM64, x86 etc.
* Gas charge is pre-estimated by tea-codec function before execution.&#x20;
* No real-time gas measurement, and no way to break from the function if the gas limit runs out.

## Wasm function

* Application-level functions.
* Can be written by any developer.
* Compiled to WebAssembly (Wasm) code, executed inside Wasm runtime.
* Capable of real-time gas measurement. Will break and return if gas limit runs out.

Devs can only write Wasm functions, and that’s ultimately the extent of what endusers can interact with. Although the apps they write can call native functions, developers can’t write native functions (system functions) because of the security risks.

## Billing for Functions

We can measure how much computation is being done by WASM function, and the WASM function cost can be deducted from the gas limit in real time. The gas limit encompasses the entire call stack, i.e. the entire chain of functions called. Once the gas limit runs out, the WASM actor will immediately return with an error code “run-out-of-gas-limit”.

We can’t currently measure the billing costs of the native function calls that a TApp makes in real-time so we must estimate them. Stated differently, TEA can’t measure itself .. but it can measure what’s running on top of it. So we estimate what each call costs based on what our “best guess” of what it costs because we can’t get real-time costs for the native functions. Because we cannot measure the real-time cost of native actors, a gas limit isn’t applicable in this case.

![](https://cdn-images-1.medium.com/max/1200/1*PdBoSDmyFaGHpR_0lE6ixA.png)

## Functions vs Actors

Actors are a compiled document of related functions. For more information, please visit our [FAQ](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/050_functions/t-rust/obsidian/_gitbook-dev-docs/050_functions/actors-vs-functions.md).


# Glossary


# Actor

An actor in the TEA project is an executable module. It works as a dynamic link library. It can be written in any programming language but needs to compiled into the WebAssembly format. At runtime, it's loaded into the [mini-runtime](/z_glossary/mini-runtime). The mini-runtime waits for the incoming request, parses the request, finds the corresponding actor, and dispatches the request to the coresponding actor's handler function. The handler function handles the request and then generates a response back to the mini-runtime. The mini-runtime then sends back the response.

In this case, the actor works as a Function-as-a-Service Lambda.

## Some Notes

There are many limitations for actors. For example:

* The actors are stateless. You cannot store any state inside the actor.
* The actors cannot control anything besides its own internal memory. That means it cannot send network data, cannot read/write any file, and cannot read/write any memory outside of its own.
* The actors are short-lived and cannot keep running as a long-running service. Once the function executation is done, it loses all resources that it's occupied.

But you can use [provider](/z_glossary/provider)s to overcome those limitations. Of course, the providers will check the [capability](/z_glossary/capability) of such an actor. If the actor doesn't have the proper capability, the request will be rejected. This is one layer of the security control.


# Adapter

The **adapter** is a module within the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) that lives outside the enclave. Its goal is to accept http calls from outside world (eg. browser, other nodes). In our TEA Party example, only http adapter messages are handled and passed through to `handle_adapter_http_request`.

See the following code sample:

```
fn handle_adapter_request(data: &[u8], section: &str) -> HandlerResult<Vec<u8>> {
	let adapter_server_request = rpc::AdapterServerRequest::decode(data)?;
	debug!(
		"got adapter section: {}, request: {:?}",
		section, &adapter_server_request
	);
	match section {
		"http" => match adapter_server_request.msg {
			Some(rpc::adapter_server_request::Msg::AdapterHttpRequest(r)) => {
				let res = handle_adapter_http_request(r)?;
				return Ok(res);
			}
			_ => debug!(
				"ignored adapter ipfs server request message: {:?}",
				&adapter_server_request.msg
			),
		},
		_ => {
			debug!(
				"ignored adapter section ({}) message: {:?}",
				section, &adapter_server_request
			);
		}
	}
	Err(DISCARD_MESSAGE_ERROR.into())
}
```


# App AES Key

Every TApp has an AES key. This AES key is used to encrypt/decrypt any data stored to hosting nodes' local IPFS or OrbitDB databases.

## Generating the app's AES key

When a TApp is first created in the TAppStore, the GenreateAesKeyTxn is created and then executed in the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md).

During execution, a random AES key is generated in the state.

The state machine algorithm can keeps the random AES key consistent among all state machine nodes.

## A hosting node's access to this AES key

When a hosting node starts to host a TApp, the TApp actor can access the AES key from the state machine. The state machine only sends the AES key if the requestor is the TApp's actor.


# AuthKey

## AuthKey

AuthKey is similiar to a session in web 2.0. It's used to identify users and their authority of operation in TApps.

### Why not use username/password?

Almost all user activies happen in layer2 instead of layer1, but the user authentication happens in layer1 only. The only thing we can determine via user authentication is the user signature using a blockchain wallet (such as Metamask or Ledger). You may ask why we cannot use the traditional username/password as most web 2.0 applications typically use. The reasons are:

* We try to make all users annoymous by not connecting user\_id with any personal information, such as email/phone number.
* Saving passwords (even hashed) anywhere in layer2 may attract hackers.
* Many users will not set a strong password to protect themselves.
* Many users forget their passwords and we can hardly help them to get it back or reset it due to the annoymous nature of blockchain wallets.

Because of these issues, we would like to use the end user's blockchain signature as the solo way to identify them.

### Operation of Auth in AuthKey

The AuthKey includes the allowed operations list. User will get promoted in the UI before signing the authkey on what operations are allowed (allowance to spend by this TApp (max expense), Allowance to transfer, Withdraw etc.)

Tihis operation list is a JSON string that's signed using the user's blockchain private key. [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) will not verify this signature, but the [provider](/z_glossary/provider) inside the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) will. Even if the [state\_machine\_actor](/z_glossary/state_machine_actor) was coded by the developer to allow transfering user's funds, the [provider](/z_glossary/provider) of the [state](/z_glossary/state) will double check to confirm if this operation is still allowed by the user. In this case, even if the developer is a bad actor that's trying to steal user's money, it will be blocked by the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) eventually.

In other words, the design of TEA Project allows for the worst-case assumption that a developer's trying to steal users' money but the AuthKey logic inside the [provider](/z_glossary/provider) of [state](/z_glossary/state) prevents this from happening.

### How does it work?

The TApp developer will set an AuthKey profile string (in JSON format) based what the end user's supposed to do after login. This profile should only include the necessary operations. If any more than the required operations are included it may cause the end user to reject signing the transaction and even report the TApp to the DAO.

When a user logs in to a TApp, this AuthKey profile string will be part of the to-be-signed string and shown in the wallet UI. The end users should review these allowed operations before signing.

The signing process is the same as using Metamask to sign an Ethereum transaction. The only difference is this signed string will not be sent to the blockchain, but to the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) instead.

Once signed, the user agrees that this TApp can do what's been allowed in this string. The signed string is sent to the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) and stored there temporarily with a nonce handle. This nonce handle is called **AuthKey**. This AuthKey is returned to the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) and the user's browser. Every time this user wants to run any [queries](/z_glossary/queries) or [commands](/z_glossary/commands) that require authorization, this AuthKey will be sent to the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) and eventually to the [state\_machine\_actor](/z_glossary/state_machine_actor). When the [state\_machine\_actor](/z_glossary/state_machine_actor) actually calls the [provider](/z_glossary/provider) of [state](/z_glossary/state), the AuthKey will be checked before it can actually be allowed to run. If there is any violation, an error will be thrown.

## AuthKey expiration

Like regular sessions in web 2.0, an AuthKey has an expiration time. If the user stops sending any activity for 30 minutes (this length of time is configurable), the AuthKey is expired. The end user has to re-login to create a new AuthKey to continue operations.

## AuthKey security

If a sniffer get this AuthKey, he can impersonate the user and cheat the system. So the security of AuthKey is very important. In [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) and [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md), the AuthKey always stays inside the hardware [enclave](/z_glossary/enclave). During transportation between [enclaves](/z_glossary/enclave), TLS security is always applied. Between browser and the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md), a special end-to-end encryption is applied to keep the AuthKey secure.


# back\_end\_actor

Using the TEA Party TApp as an example, the [party-actor](/z_glossary/party-actor) compiles to the [actor](/z_glossary/actor) that runs inside a [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md).

Since it's an [actor](/z_glossary/actor), it's loaded and runs inside the [enclave](/z_glossary/enclave) (also called the [mini-runtime](/z_glossary/mini-runtime)).

The only thing that the back-end actor does is handle incoming requests.

This back\_end\_actor is different than the [state\_machine\_actor](/z_glossary/state_machine_actor) which run inside the enclaves of the [state machine replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)s. Those [state machine actors](/z_glossary/state_machine_actor) handle the [queries](/z_glossary/queries) and [commands](/z_glossary/commands) that directly interact with the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md). In traditional web 2.0 applications, these are usually called **Stored Procedures** that run inside the database server.


# Birth Control

## The ecological balance

The TEA Project ecosystem has an ecological balance between computing resource supply in the form of CML and computing resource demand in the form of TApps. CMLs represent the computing supply as CML nodes are capable of executing computing tasks within their protected [enclaves](/z_glossary/enclave). TApps represent the demand for these resources as they're the apps that consume computing services.

The DAO monitors the usage (idle time and waiting time) of every CML. If the majority of CML are waiting, it means supply is over demand. If the majority of CML are busy but the TApps have tasks waiting in line to be executed, then that means demand exceeds supply.

Based on the supply/demand ratio, the DAO will automatically increase or decrease the amount of new CML seeds released to the marketplace.

Another indicator for computing supply and demand on the network is the price of CML as reflected in the auction marketplace. If the auction price is too high, the DAO should increase the CML seeds supply (and reduce the supply if prices are too low).

The adjustment on CML supply is made through the DAO governance. Any of these determining factors can be changed by DAO voting. During the first two years of the TEA Project's operation, the DAO is not mature enough and the community is not big enough for voting. During this early stage, the project team will control the birth rate of CML. After 2 years, the DAO will take over the birth rate control programmatically based on the supply and demand factors mentioned above.


# Blockchain Listener

All [state machine replicas](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md) nodes run a layer-1 client (either a full client or a light client). This layer-1 client will notify layer-2 when layer-1 events are triggered. The layer-2 runs a monitoring process that filters all events, only picking the events that are in the "waiting list" and then calling the layer-2 [state machine actor API](/z_glossary/state_machine_actor).

In the future, when the TEA Project is running above multiple layer-1 main chains, there would be multiple blockchain listeners for each main chain.


# Capability

**Capability** is a property when building a TApp actor. The developer needs to sign the actor executable with a list of capabilities. Each capability is a passkey to call a specific provider when it's loaded into the [mini-runtime](/z_glossary/mini-runtime).

The list of capabilities of any actor is public information. If can be verified by all TEA DAO members.

If an actor is not signed with a specific capability, even if there's code in this actor trying to call the specific provider API, it will be rejected. Furthermore, a violation will be reported that may cause further punishment.

The developer who signs a capability will need to carefully inspect if this capability is absollutely necessary. The more capabilities the developer signs, the more security concerns other users may raise.


# CML Auctions

Miners who wish to deploy a node on the TEA Project ecosystem will need to plant a Camellia (CML) NFT into their mining machines. These act as mining licenses for the mining nodes and record important metadata about the node's hardware, the Camellia's age, its credit history, and the machine's capabilities. Most miners will be interested in purchasing a hosting CML which will allow them to host TApps on the network.

## Every CML must be replaced

Every Camellia NFT has a life cycle: it’s born from a seed, grows into a tree, and then eventually dies over a span of approximately 2 years. The productivity of the CML will follow this timeline as well: it's not very productive in the beginning of its life. But as it grows up, it becomes more productive and generates larger amounts of revenue. When the Camellia gets older and starts approaching the 2 year mark, its productivity drops. Eventually, it will reach the end of its life cycle and die. Miners will then need to buy a new Camellia seed and plant it into their machine to start over from the very beginning.

## Determinants of CML supply

There will be a cap of 10,000 hosting CML during the first two years of the ecosystem. Any limits beyond that will be determined by a DAO governance vote.

The supply of tokens released to be sold on the marketplace through auction is determined algorithmically by the DAO. If there are many idle miners on the network, then demand is relatively low and no new seeds will be released to the marketplace. Conversely, if there's no slack in the system and network miners are near their hosting capacity, then more CML seeds will be released for auction in an effort to bring more hosting nodes online to host TApps.

## CML seeds are purchased through an open auction

CML is purchased through an open auction process where the DAO (or individual users) list their seeds for sale at their desired price. Once a buyer succesfully bids on a CML, the TEA that they used to purchase the CML will be burned by the DAO.


# Commands

In contrast to [queries](/z_glossary/queries), commands can change the state in the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md).

In order to keep the consistency of the state machine, we cannot allow the hosting node to ask one state machine node to change its state directly. We have to put the change request - actually a command - to a [conveyor](/z_glossary/conveyor). The conveyor algorithm will make sure all state machine nodes get the same sequence of all comands, and eventually update all of their states to the same new state.

Because it's a sync call, the caller (hosting node) cannot get the execution result of this command immediately. Instead, the caller will poll the result after a few seconds to get the result.

![5](https://user-images.githubusercontent.com/86096370/159343544-f349473c-19ba-4c51-a6cd-4442626eaa02.png) ![6](https://user-images.githubusercontent.com/86096370/159343552-d67709f1-f2cf-4651-8405-f0d9e6b41e4e.png)

![7](https://user-images.githubusercontent.com/86096370/159343554-53cd8bf5-eba3-40d8-889a-039766c39e9b.png)


# Consensus

## Thinking outside the box

Consensus is the most important concept in the blockchain world. It enables distributed nodes to agree on what the next state should be. There are many different types of consensus for all the different blockchain projects. And still there are new consensus algorithms being invented every other month. Although we tried to fix its shortcomings, the blockchain is still far from the efficiency of cloud computing. The primary reason it's not able to keep up is consensus. The nature of blockchain requires its constituent nodes to regularly take time (every few minutes or seconds) to communicate with other nodes and run complex algorithms to determine the next block. This makes the blockchain slow and costly, a process that cloud computing doesn't require. You've probably never heard of the TPS concept in the cloud computing world since it has the big advantage of centralization. The nodes can fully trust other nodes without running any kind of complex consensus. Can we find the best blockcahin consensus that can run as fast as cloud computing? To try to solve this problem, we'll need to start thinking outside the box.

## The best consensus is no consensus

As we mentioned above, as long as there's a consensus, a blockchain can never reach the same speed as cloud computing. The question of "what's the best consensus?" is actually a trick question. It turns out that no consensus is the best consensus .

Assuming there was, by magic, no need to run consensus: every standalone node can make the correct decision on what the next state is supposed to be. Let's imagine that all of the nodes can magically reach the same state. Now that we've set the goal, let's see how we can make this magic into reality.

## The key is the sequence of events

We must take into consideration that the whole blockchain is a state machine. An event (we usually call these "transactions") is the outside trigger to change the state inside of the state machine. Every node is a replica of the state machine. As long as every node can get the same sequence of events and update the state accordingly, the new state will be the same across all replicas.

If we review all of the existing consensus algorithms, no matter what proof-of-whatever they're based on, they all do the same thing: make all nodes agree on a single sequence of events.

Now, can we get the sequence of all events without using consensus?

## Proof of Time

As long as we stay on the earth without being able to travel at near light speed, we can consider that time is a stable physical value. If we give every event a timestamp before sending out to replicas, this timestamp can be trusted. Then all the replicas can sort events based on the timestamp without communicating with others. Of course, given the network latency, we allow a grace period or buffer period where replicas wait prior to executing the event.

Actually using time as the RoT (Root of Trust) of consensus is commonly used in cloud computing (e.g. Google Spanner). But it's not widely used in blockchain world simple because blockchain cannot trust other nodes as centralized cloud computers can.

Now the question is can we trust the timestamp attached to an event since the source of the timestamp was created outside of the blockchain?

Yes we can by using another RoT (Root of Trust), the [tpm](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/tpm.md) chip.

## Proof of Trusted Computing

TEA Project is a project that relies on a hardware RoT. Every TEA node needs to have the [tpm](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/tpm.md) chip built-in. The TPM chip uses Trusted Computing technology to collect the evidence of hardware integrity. That TPM data is verified by other TEA nodes (verifiers) via [remote\_attestation](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/remote_attestation.md) (RA). The decision is made by the verifier independently, and final judgement is done by the blockchain's BFT. If there's any change in a TEA node, no matter hardware or software, it will be detected by a verifier and furthermore marked "malicious" in the blockchain. Other TEA nodes will immediately reject communication with this bad actor.

If all the TEA nodes are protected by a TPM chip, all data generated inside this node (actually inside the enclave of this node) can be trusted. This includes the timestamps generated by the GPS moudle that we attach to events.

## GPS as time source of atomic clock

Although we can trust the TEA node that's protected by a TPM, the internal hardware clock (most likely quartz clock) cannot be trusted. It's not acurate and precise enough to be used to sort events. Requiring every TEA node to have an atomic clock built-in is not practical financially. The best solution is to use GPS satellites. The GPS satellites send a free time signal to all GPS receivers. We don't need to use the signal to calculate geolocation, we instead only need the time as an event timestamp. Because it's under the watchful protection of the TPM, the timestamp can be trusted.

## Conclusion

All TEA nodes have a TPM protected [enclave](/z_glossary/enclave). The TPM also protects the GPS receiver and the timestamp it generates. All events generated from those TEA nodes will have a timestamp attached. The events are sent to a group of [state machine replicas](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)s. The events are inserted and sorted in the [conveyor](/z_glossary/conveyor) before eventually being executed by the [state machine actor](/z_glossary/state_machine_actor). When the events are executed, it changes the [state](/z_glossary/state).

## Notes

#### Sync messages between replicas

Although no conensus is required between replicas, but we still need to keep the data synced between them. This is mainly done to fill in the missed events and to get the earliest timestamp for the same event. The details are explaned in the [conveyor](/z_glossary/conveyor) article.

#### Event or Command?

In the TEA Project, we call events that can change the state [commands](/z_glossary/commands). If an event is just a query of the current state without changing the state, we call these [queries](/z_glossary/queries).

We use event here in this article to be consistent with the common terminologies used in distributed computing.

If an event is just a query, it doesn't need to go through the whole grace period process. It goes direclty to the state machine to execute its query. See [queries](/z_glossary/queries) for detail.

#### Continuous state updates

There is no block in our new consensus. There is no need to wait every few minutes or seconds for the next block. The TEA Project state machine is continuously updating similar to a distributed database without any central control.

#### Grace period (or buffer period)

When an event is sent to the [state machine replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md), it will not be executed immediately. It will stay in the [conveyor](/z_glossary/conveyor) for a short period of time. During this period, the sequence of events will be re-ordered based on timestamps. When they are eventually executed, the sequence is confirmed. We're actively testing the best length of the grace period. At the time this article was written, we've set the grace period at 3 seconds.

#### Finality

As long as the event is executed in the state machine, it has reached finality.

#### Learn more

Please go to [conveyor](/z_glossary/conveyor) and [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) to learn more.


# Context

Context (in the state machine) records a list of operations that execute [commands](/z_glossary/commands), which **should** be applied to the [state](/z_glossary/state) if committed. But before the final commit, the state itself is not changed, and only to-be-changed operations are stored in the context.

The goal of context is an atomic commit. All the operations are either committed successfully or not committed at all.

During the execution of [commands](/z_glossary/commands) in the [state\_machine\_actor](/z_glossary/state_machine_actor)s, all operations will be inspected to make sure they would be successfully commited. This is very important. All operations inside context need to be guaranteed successful. If any operation would fail, this command is aborted and the context will be dropped. In that case, nothing will be committed, and the state will not change at all.

In order to make sure that all operations inside a context are guaranteed to be committed successfully, we require commands to be executed in a single thread. All execution functions are **pure functional functions**. That means all required parameters have been included in the function parameters, and there are no additional external inputs or conditions. The function result is deterministic. **Deterministic** is an important requirement in the [state\_machine\_actor](/z_glossary/state_machine_actor) handler functions. If determinism is not guaranteed, the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) in a different [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md) may not sync. In other words, the state machine **cannot reach consensus** and will cause the [state](/z_glossary/state) to be out of sync.


# Conveyor

The conveyor is an algorithm to make sure all state machine nodes have the same order of transactions. This is necessary as there will occassionally be conflicts due to network latency and the redundancy of transactions sent to multiple replicas. The conveyor algorithm is designed to shuffle the transaction order, which includes merging duplicate transactions and re-ordering transactions according to their timestamps.

* Any particular hosting CML node shouldn't change the state of the state machine directly.
* It requests to change the state by sending its transactions (along with followup messages) to the conveyor belts of two or more replicas.
* After a set period of time, the conveyor belt ensures that transactions have reached a steady order before all state machine actors update to the same new state.
* The updated app state is sent back to the application which updates its interface accordingly.

TApp developers are responsible for sending out their application's transactions and followup messages to a minimum of 2 replicas (this is the default wheen using the API). More replicas may be chosen by the developer in certain instances according to the importance of the transaction to their app.

## Workflow of the conveyor belt algorithm

The hosting CML node receives user interaction, generates a hash of the transaction and sends it to the conveyor belt of two or more replicas. The timestamp of this send was recorded but not able to be included in the transaction, therefore a followup message must be sent out that includes:

* the hash of the previously sent transaction.
* the timestamp of the previously sent transaction.
* if this is not the first followup message (i.e. the transaction reported to other replicas' conveyor belts has already issued their followup messages), then the followup message will also record the existing timestamps as recorded in the other replicas' followup messages.

![1](https://user-images.githubusercontent.com/86096370/159138351-9230a110-1ff3-483a-9457-7581b36706e8.png)

![2](https://user-images.githubusercontent.com/86096370/159138355-4f6d7c6d-e037-4046-8a87-fc4a85a0e11d.png)

## Conveyor belt: mutable vs inmutable areas

Every followup message gets converted to a tsid which references a txn. The tsid and not the txn itself is what actually is sent to the conveyor as the tsid is easier to sort.

Each replica's conveyor belt has a mutable section at the front followed by an immutable section.

* **Mutable section**: transactions can be re-ordered in this section based on the earliest timestamp recorded in the tsid. Note that any particular replica's conveyor must receive both the transaction and its corresponding tsid within this mutable block of time. If either is missing, the tsid of the transaction is dropped from the conveyor before it reaches the next immutable section.
* **Immutable section**: after a tsid has been on the conveyor belt for a mutable period of time, the tsid passes on to the immutable section. Transactions referenced in the immutable section cannot be re-ordered; however, any conveyor's immutable section that's missing a tsid from other replicas will have the missing tsid added to its conveyor in the same relative order as the replica it synced with.

A consequence of this conveyor algorithm is that even though a particular replica will have to drop a late arriving transaction (arrives after mutable period of time and is unable to be placed in the immutable section), the replica's conveyor will still be able to add the tsid of the transaction to its immutable section through syncing with other replicas.

## Consensus on the transaction order

The end goal of the conveyor algorithm is to reach a consensus on the order of transactions. In the end, all replica conveyors should match the same order. This is achieved through each replica's immutable section of the conveyor.

* Once at least 50% of all replicas agree on the transaction order in their immutable section, this will act as a successful vote on the transaction order contained in the immutable section.
* After a few sync intervals, the immutable sections of all replicas will reach consensus.
* Once consensus is reached on the order of transactions in the immutable section, the transactions pass to the execution point of the conveyor.
* From the execution point, the transactions are sent to the state machine actor.
* The state machine actor updates its state according to the transactions the replicas send to it.

![3](https://user-images.githubusercontent.com/86096370/159138357-b1c0729a-04e8-4ad6-87b4-b9b39cbf71fb.png)

## Sending the updated state back to the apps

The successfully confirmed transactions have updated the current state of the app. These state changes must now be sent back to the app from where they first came. The final workflow where the state changes are reflected back in the actual app look like this:

1. After the immutable section of the replicas' conveyors has reached a consensus, an executable actor sends the transactions to the state machine actor in the replica.
2. The state machine actor deals with the possibility of failed transactions:

* If it's successful, then modify / update the app state.
* If the transaction is unsuccessful, then issue an error message and don't modify the state.

3. A notification on the result of the previous process, either a **success** message or an **error** message, is then sent back to the original application.
4. If the application wants to update its UI to reflect the updated state for transactions that successfully updated the state, then the app must use issue [queries](/z_glossary/queries) to get the updated state.

![4](https://user-images.githubusercontent.com/86096370/159138361-4a7a5769-5d62-4602-9216-4453b27a39ae.png)


# Conveyor: Mutable vs Immutable

## Conveyor belt: mutable vs inmutable areas

Every followup message gets converted to a tsid which references a txn. The tsid and not the txn itself is what actually is sent to the conveyor as the tsid is easier to sort.

Each replica's conveyor belt has a mutable section at the front followed by an immutable section.

* **Mutable section**: transactions can be re-ordered in this section based on the earliest timestamp recorded in the tsid. Note that any particular replica's conveyor must receive both the transaction and its corresponding tsid within this mutable block of time. If either is missing, the tsid of the transaction is dropped from the conveyor before it reaches the next immutable section.
* **Immutable section**: after a tsid has been on the conveyor belt for a mutable period of time, the tsid passes on to the immutable section. Transactions referenced in the immutable section cannot be re-ordered; however, any conveyor's immutable section that's missing a tsid from other replicas will have the missing tsid added to its conveyor in the same relative order as the replica it synced with.

A consequence of this conveyor algorithm is that even though a particular replica will have to drop a late arriving transaction (arrives after mutable period of time and is unable to be placed in the immutable section), the replica's conveyor will still be able to add the tsid of the transaction to its immutable section through syncing with other replicas.

## Consensus on the transaction order

The end goal of the conveyor algorithm is to reach a consensus on the order of transactions. In the end, all replica conveyors should match the same order. This is achieved through each replica's immutable section of the conveyor.

* Once at least 50% of all replicas agree on the transaction order in their immutable section, this will act as a successful vote on the transaction order contained in the immutable section.
* After a few sync intervals, the immutable sections of all replicas will reach consensus.
* Once consensus is reached on the order of transactions in the immutable section, the transactions pass to the execution point of the conveyor.
* From the execution point, the transactions are sent to the state machine actor.
* The state machine actor updates its state according to the transactions the replicas send to it.

![3](https://user-images.githubusercontent.com/86096370/159138357-b1c0729a-04e8-4ad6-87b4-b9b39cbf71fb.png)


# enclave

## Enclave

In the TEA Project, we use hardware TPM to verify a special area called an **enclave** is trusted. The enclave is a special area inside of a mining node. The area *outisde* of the enclave is called the **parent instance** of the enclave.

A parent instance is a regular area that the OS or the miner (human) can access. But the enclave is a special area that the OS and human miners cannot access.

That is to say, anything that's running inside the enclave is unknown to the outside world. It can be compared to the physical concept of a "blackhole horizon". However, an enclave is not a blackhole as the computing result can be sent back to the outside world.

### The rule of data transfer in and out

If a data (or code) is supposed to be secret when it's tranferring out from the enclave, it will be encrypted. After encryption, it can be transferred to other nodes or stored to any storage. But when it's loaded into the enclave again, it will be decrypted.

### The key of an enclave

The encryption key is the TPM's hardware key. This key will never be exposed to outside world (see the TPM security documents).

Besides the main key generated by the TPM hardware, there are derived keys that will be used for multiple purpose. All of them will stay inside the enclave's memory at all times. If they have to leave the enclave, they'll be encrypted using a higher level key with the very top level key being the hardware TPM key.

### There's no network or file system inside an enclave

Inside of an enclave, a special stripped version of NixOS (a distribution of the linux operating system) is used. In order to reduce the attack surface, only a few core features are compiled into this special version of the NixOS. Some popular features are forbidden; for example, a file system or networking will not exist inside the enclave.

### Communication between enclave and parent instance

Since there's no file system or network inside the enclave, an actor's only channel to contact the outside world would be through the [vmh](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/vmh.md) (Virtual Messaging Hub). The VMH API is wrapped inside providers. If an actor has a [capability](/z_glossary/capability), the code in this actor can call the provider's API to send messages to the VMH. The outside components will receive such messages asynchronously.

### Remote Attestation

The TPM genreates the PCR hash array against the enclave. When a verifier is assgiend to remote attest a testee, the testee will send the PCR data signed by the TPM. The verifier first verifies the TPM signature and then verifies the PCR value against the testee's publicly revealed information. If they match, the verifier signs a "true" result to layer one. If not, the verifier signs a "false" result to layer one.

Layer one (blockchain) runs basic BFT to consider whether a testee passes or fails remote attestation or not.

The content of the PCR hash includes all hardware and software fingerprints in the enclave. Any changes to the enclave may cause remote attestation failure.

## Only verified enclaves can join the TEA network

Every enclave will have a [tea\_id](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/tea_id.md). This TEAID has an entry in our layer one that stores the verification status. When an enclave wants to contact another enclave, they'll first check their TEAID verification status. If the status is not "verified", the connection will not be estabilished.


# Followup

The TEA Project [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) requires every event ([commands](/z_glossary/commands) or [queries](/z_glossary/queries)) to have an acurate and trusted timestamp attached. Because we make an allownace that the P2P network might be unreliable, messaging on the network has built-in redundancy. That means for any event, the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) has to send at least two identical messages to two different [state machine replicas](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md). The logic in the [back\_end\_actor](/z_glossary/back_end_actor) is single threaded, and the two identical messages will have different timestamps as they are sent one after another. To double-check that they're identical, we designed it such that a followup message will be sent right after any message is sent.

The information in these followup messages include:

* The hash of the event message just sent out.
* The actual timestamp of when that message was sent out.
* If the event message is a duplicated (redundant) message, use the timestamp of the first time it was sent (i.e don't use the timestamp of the duplicated/redundant message).

Using this design, the multiple event messages will have an identical message body and identical followup messages. Because the timestamp (which is the only data that could be different) is set to the timestamp of the first message that was sent, the second (or any later) message's sent-timestamps are ignored.


# Front-end

The TEA Project isn't a front-end framework. Developers can use whatever front-end tech stack they're most comfortable with.

For every TApp, the front-end code could be comprised of JS/HTML/CSS code that's stored in IPFS (or another type of decentralized storage). The CID (Content ID, actually the hash of the content) is the key to retrieving the content.

When the end user loads a TApp, it actually loads the static resources refereced by the CID from one of the IPFS nodes.

The front-end must be a **static** resource. All dymanic content will be queried from the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md).


# GlueSQL

[GlueSQL](https://github.com/gluesql/gluesql) is a SQL database library written in Rust.

TEA Project uses GlueSQL as an embedded SQL database **inside** of a [state machine replica's](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md) enclave. All data is stored in RAM only. The [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) keeps all SQL states consistent across all replicas.


# GPS

We need GPS but we don't use this for navigation. Our TEA nodes are stationary and don't move on the street. Instead of location, we use the acurate timestamps from GPS satellites. Every GPS satellite has an atomic clock, and it constantly sends time signals to any terrestrial GPS receiver. We use this as the source of the timestamps for all events.

To learn more about how we use the timestamps, click [conveyor](/z_glossary/conveyor) and [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md).


# Hosting Actor Handlers

The hosting actor has the same functionality as that of a back end in traditional web development.

The state actor has the same functionality as "stored procedures" in traditional web development.

TEA's back end is a series of handlers that handle requests from end-users, process the business logic, and then return the response back to the end user.

Typically there are three types of requests coming from the end users.

* Query.
* Send transaction.
* Get results.

## Send query

Query will not modify the state, it will just get the current state of the state.

In some cases, the hosting nodes have a local cache of state, so it will just return the result directly. This is a sync call. In other cases, the hosting nodes don't have a local cache of the state, so it cannot get back the result immediately. It has to send another request to the [state machine actore](/z_glossary/state_machine_actor) for the latest state. In this case, the hosting node will response a UUID as query-stub for future result lookup. This call is considered an async call. The future looking up for result is "get results" request.

## Send transaction

Similar to query, but transaction (sometimes short for txns) will change the state. it will either modify the token balance or modify the SQL database.

Hosting nodes have no way to modify the state inside of their nodes because the state is owned by a group of state maintainer nodes. The hosting node instead can send a txn request to the state maintainer nodes to modify the state. No doubt, this is an async call. The hosting node will responsd with a UUID as the query-stub for a future look-up result.

## Get results

Once an async query or txns have been returned, the end-user will receive a UUID as stub. The front end client will frequently send "Get Result" request to the connected Hosting node for the result of such UUID. Because there is no way to predict when the result will be ready, the front-end may need to constantly ask for result if the answer is "not ready yet" until 1) the result is ready and returned, or 2) timed out as it would be unlikely there would be any result in the future.

## Conclusion

Development of the hosting actor is nothing but to implmenet those three types of requests from front end. However, there are some "must-have" system level request handlers that all actor will need to handle. They are called [system\_handler\_for\_actors](https://github.com/tearust/t-rust/blob/master/docs/dev_portal_design/system_handler_for_actors.md). In most cases, developers do not need to modify the code and let it work by default.


# Hosting CML

This is usually called a web server in traditional cloud computing. In the TEA Project, since it's fully decentralized, there's no such thing as a web server. Instead, any miner can plant a CML into a mining machine to enable their machine to host TApp backend actors.

This machine is usually called hosting CML, or host. In the past, we've referred to hosting nodes as B CML.


# hosting\_profitability

## Hosting Profitability

Miners deploy their mining machines on the TEA network to earn profit. To start earning on the network, miners will need the following:

* A hosted or local machine. Mining hardware is designed to be affordable for miners as they'll just require a Raspberry Pi with GPS and TPM chips. The TEA Project also runs on AWS Nitro which is therefore an option for miners who don't want to run local hardware.
* A CML NFT. Camellia (CML) NFTs are needed as a mining license to activate mining nodes. Hosting CML are purchased through [CML auctions](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/cml_auction.md), an open process where winning bids are taken in TEA (which is burned) in exchange for CML.

## How miners determine the potential revenue?

There are three types of mining available:

* A CML state machine validator mining. A CML nodes have the important task of maintaining the TEA Project's state machine. Because of its importance, very few if any ordinary users will be able to run an A CML node for at least the first 2 years post mainnet launch. A CML earn TEA rewards at the rate shown in the following document: [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md).
* CML hosting mining. When a user says they want to mine on the TEA Project, they will probably be running a hosting CML node. In addition to TEA public service rewards, hosting will earn a gas fee (from end-users) for providing the hosting infrastructure as well as the Harberger Tax payouts (from the state maintainer nodes).
* Private CML availability attestation mining. Private CML mining is earned through making sure hosting CML nodes are online. Since there's only a modest reward for performing this public service, we won't discuss private CML mining as a viable form of profitable mining in this document.

### Other types of profitabilities in TEA

There are other forms of staking and mining available to earn revenue on the TEA network. Note that all of the staking tokens listed below are issued along a bonding curve where an increase supply results in an increase in price.

#### Staking to hosting CML nodes

Staking to B CML nodes is a way to earn a share of mining revenue without having to setup a mining machine. Users will buy miner staking tokens for an individual B mining node in order to share in a mining machine's rewards, either as TEA revenue or TApp token dividend rewards. More info is available in the following document: [staking\_to\_hosting\_CML](/z_glossary/staking_to_hosting_cml).

#### Staking to a TApplication (TApp)

To participate in the revenue generated by a TApp, a user can buy that TApp's tokens. Every time a consumer uses a TApp, the developer gets their **theta** percentage share of the consumer's TEA payment and the rest is injected into its TApp token's bonding curve. The new TApp tokens that are generated from this event are distributed proportionally to existing TApp token holders. More info is available at [staking\_to\_tapp](/z_glossary/staking_to_tapp).


# Magic of WASM

[WebAssembly](https://webassembly.org/) is getting more and more popular in the blockchain world. This might be unexpected since it was originally designed to run inside the browser. But Javascript was originally designed to run inside the browser as well, and it's now common to find Javascript anywhere that code can run.

There are many reasons why the TEA Project uses WebAssembly as the execution format. To name a few:

* Compact size
* Security by design
* Additional security by virtue of running inside our [mini-runtime](/z_glossary/mini-runtime) which sits inside our hardware [enclave](/z_glossary/enclave)
* Can be compiled from many different high-level programming languages
* Open-source

In this article, we only focus on the security part.

## No\_std or std? Smart contracts or fully programmable?

For most new blockchain developers that start to write Substrate code, the non\_std requirement presents the first barrier. Unlike most applications, Substrate requires the no\_std feature otherwise your code won't be compiled to run in Substrate. Most of the existing Rust crates are written for the std library. Unfortunately, developers cannot use them directly, which makes programming in Substrate much harder.

Of course, there's a reason for that. Substrate wants to create a much safer environment to run Wasm code as the std library may be "unsafe" from a smart contract point of view.

In programming, there's always a tradeoff between security and functionaility. The consequence of remaining secure is that you cannot do too much within a smart contract. Again, a smart contract is not a fully-featured application; it's just a "turing complete" state machine that mostly deals with accounting. Most of the functionality of modern internet applicationd are simply not possible in a no\_std environment.

## TEA Project is not a smart contract, it's Web3

The goal of the TEA Project is to run standard Web3 applications decentralized. Running a smart contract is not the goal. So TEA has to support std which may potentially cause some security issues which Substrate didn't have to deal with. Of course, we cannot sacrifice security in the TEA Project, so we designed the following complicated model to minimize the risk.

## Wasm model as "[actor](/z_glossary/actor)" and runs inside a[mini-runtime](/z_glossary/mini-runtime)

The mini-runtime can be considered a specially designed virtual machine. It loads [actor](/z_glossary/actor)s into isolated spaces. Although this is "std" Wasm, it's still limited heavily by the mini-runtime. Because the mini-runtime runs inside the hardware [enclave](/z_glossary/enclave), the enclave is a specially designed linux mini core OS. We removed most of the common Linux components to reduce the attack surface, including the network and file system which are all gone. If any malicious code happens to run inside the enclave (we don't how that would happen, but let's just assume), it will not cause any further damage since there's no network or file system to break.

## Providers and capabilities

If the actor wants to access anything outside of the enclave, it has to call [provider](/z_glossary/provider)s with a preset [capability](/z_glossary/capability). If the actor code is not signed with the specific [capability](/z_glossary/capability) by the original developer, or the code tries to call the provider unexpectedly, it will be rejected and result in a penalty.

Let's imagine that a hacker modified an actor's execution binary code.

The first issue is that the CID will no longer match and the mini-runtime cannot load.

If it can break this first security barrier, the capability signature check will fail since the developer did not sign this actor with an unauthorized capability.

Let's imagine that it can somehow break this barrier as well, and somehow it gains this capability and can successfully call the provider inside the mini-runtime. The provider has additional checks before invoking any important functions. Those additional checks include (most commonly) the caller actor ID, destination peer\_id, destination actor\_id, traffic pattern etc. It will reject any suspicious function call and report it to Remote Attestation.

The providers are currently written by the TEA Project team, not by 3rd party open-source developers. Upgrading [provider](/z_glossary/provider)s is a very sensitive workflow and care is taken to prevent any malicious code getting introduced into the [mini-runtime](/z_glossary/mini-runtime).

## Last barrier, the [birth\_control](/z_glossary/birth_control) policy

Imagine that somehow the hacker has compromised less than 1/3 of the mini-runtime and malicious providers are introduced. As long as there are still more than 2/3 good nodes running, after a few seconds, the next sync will cause a state mismatch error. Due to BFT consensus, those 1/3 nodes will be quarantine and eventually removed from the network followed by slashing their deposit.

So as long as we keep the [birth\_control](/z_glossary/birth_control) to grow the nodes slowly to ensure we always have over 2/3 good nodes, the system will be secured.


# mini-runtime

## Mini-runtime

Mini-runtime is a WebAssembly runtime made by the TEA Project team based on the existing WasCC runtime.

The mini-runtime has a host executable and a bunch of [providers](/z_glossary/provider) and [actors](/z_glossary/actor). The actors are WebAssembly modules containing [lambda](https://en.wikipedia.org/wiki/Lambda_calculus) functions. The providers are native executable libraries that provide features actors can call. Usually these features are forbidden from being used by actors (for example, networking or saving data to persistent storage (IPFS/OrbitDB)).

## Protected by the enclave

The mini-runtime is the only executable allowed to run inside the [enclave](/z_glossary/enclave). The benefits are:

* It's fully isolated from the other components of the node. The operating system has no access to the inside of the enclave. Even the owner who has full access to the node's hardware and its operating system cannot know what is happening inside the enclave.
* It's able to achieve the security as explained above without using complex math algorithms (MPC, FHE, ZK etc). This means no overhead and no energy wasted.
* Although the inside of the enclave is unknown to the outside, the TPM chip can still send verification data to the remote verifiers. If anything goes wrong inside, the verifiers will know. Of course the verifier needs to be trusted first.
* If we trusted the hardware and the code/data loaded into the enclave, the computational result can be trusted as well.


# OrbitDb

[OrbitDb](https://orbitdb.org/) is a Peer-to-Peer Database for the Decentralized Web

> [OrbitDB](https://github.com/orbitdb/orbit-db) is a serverless, distributed, peer-to-peer database. OrbitDB uses [IPFS](https://ipfs.io/) as its data storage and [IPFS Pubsub](https://github.com/ipfs/go-ipfs/blob/master/core/commands/pubsub.go#L23) to automatically sync databases with peers. It’s an eventually consistent database that uses [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) for conflict-free database merges making OrbitDB an excellent choice for decentralized apps (dApps), blockchain applications, and offline-first web applications.

In the TEA Project, every [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) has an OrbitDb instance running **outside** of the enclave.

OrbitDb is used to store large data blobs. OrbitDb provides limited non-relational database features but at a much lower cost. For a relational database, developers can use [gluesql](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/gluesql.md). For more essential account balance (money) data, we'd suggest using [state](/z_glossary/state) instead.

## Privacy protection

IPFS is open to the public. Anything stored in the IPFS can be accessed by anyone. OrbitDB is no exception. How do we protect the data in the OrbitDB? We use the [app\_aes\_key](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/app_aes_key.md)

The data used in one applicaiton is encrypted using this application AES key inside enclave. When the data is saved to the OrbitDB, it has been encrypted. It will be decrypted when again loaded into the enclave by the same application. Other application cnanot decrypt because they do not have such [app\_aes\_key](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/app_aes_key.md).

The [app\_aes\_key](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/app_aes_key.md) is stored inside the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) which is consider the top security of the whole TEA Project network. When a new applicaiton host instance starts, it will request such a AES key to the state machine. After a restricted scurity check, the instance can receive such AES key. Because the AES key only live inside enclave (both state machine or hosting nodes.), it is unknown to outside world.

## Sync

For every TApp, there are multiple hosting nodes. Every node has their own OrbitDB instance running inside the node (outside of the [enclave](/z_glossary/enclave)). They sync with each other using the standard OrbitDB sync algorithm. Please visit [orbitdb.org](https://orbitdb.org) for more details on the sync method.

Because all of these instances share the same [app\_aes\_key](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/app_aes_key.md), the data is the same across all nodes as they take advantage of the duplication provided by IPFS/OrbitDB.

## Cost

Since OrbitDB lives outside of the [enclave](/z_glossary/enclave) and is stored on a hard disk (actually IPFS), using it would be much cheaper compared to the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) (whose data stays inside the RAM of the [enclave](/z_glossary/enclave)). Of course, the state machine would be a much more limited resource and be much more expensive than hard disk space outside of the enclave.

## Eventual consistency

OrbitDB provides [**eventual consistency**](https://en.wikipedia.org/wiki/Eventual_consistency), which means you could get temporary inconsistency across all nodes. Your TApp has to handle this possible scenario in its business and UI logic.

If your data is very time sensitive and requires [**strong consistency**](https://en.wikipedia.org/wiki/Strong_consistency), please use the more expensive [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) instead.


# Order of Txns

The most important thing that consensus is trying to solve, whether it's blockchain or any kind of distributed system, is to get a sequence of transactions (or events) that all nodes agree on.

There are many types of consensus used, such as PoW (Proof of Work) and PoS (Proof of Stake). All of them are slow and costly.

In the TEA Project, we use the physical value of time from GPS satellites as the source of timestamps. All events attach a TPM protected timestamp when sending to different distributed replicas. All replicas can get the same order regardless of geolocation and network latency.


# party-actor

## Party-actor

### handle\_adapter\_http\_request

In the lib.rs file, you'll find the `handle_adapter_http_request` function. All of these branches are messages that this actor can handle.

```rust
fn handle_adapter_http_request(req: rpc::AdapterHttpRequest) -> anyhow::Result<Vec<u8>> {
	match req.action.as_str() {
		"login" => api::login_request(&serde_json::from_slice(&req.payload)?),
		"checkLogin" => {
			let req: CheckLoginRequest = serde_json::from_slice(&req.payload)?;
			user::check_auth(&req.tapp_id, &req.address, &req.auth_b64)
		}
		"logout" => api::logout(&serde_json::from_slice(&req.payload)?),
		"updateTappProfile" => api::update_tapp_profile(&serde_json::from_slice(&req.payload)?),
		"query_balance" => api::query_balance(&serde_json::from_slice(&req.payload)?),
		"withdraw" => api::withdraw(&serde_json::from_slice(&req.payload)?),
		"queryHashResult" => api::query_txn_hash_result(&serde_json::from_slice(&req.payload)?),
		"queryTappAccount" => api::query_tapp_account(&serde_json::from_slice(&req.payload)?),
		"queryTappStoreAccount" => {
			api::query_tappstore_account(&serde_json::from_slice(&req.payload)?)
		}

		"postMessage" => api::post_message(&serde_json::from_slice(&req.payload)?),
		"postFreeMessage" => api::post_free_message(&serde_json::from_slice(&req.payload)?),
		"loadMessageList" => api::load_message_list(&serde_json::from_slice(&req.payload)?),
		"extendMessage" => api::extend_message(&serde_json::from_slice(&req.payload)?),
		"deleteMessage" => api::delete_message(&serde_json::from_slice(&req.payload)?),

		"query_result" => {
			let req: HttpQueryResultWithUuid = serde_json::from_slice(&req.payload)?;
			let res_val = api::query_result(&req)?;
			Ok(serde_json::to_vec(&res_val)?)
		}
		"notificationAddMessage" => {
			api::notification_add_message(&serde_json::from_slice(&req.payload)?)
		}
		"notificationGetMessageList" => {
			api::notification_get_message_list(&serde_json::from_slice(&req.payload)?)
		}
		"testForSql" => api::send_sql_for_test(&serde_json::from_slice(&req.payload)?),
		"testForComsumeDividend" => {
			api::send_test_for_comsume_dividend(&serde_json::from_slice(&req.payload)?)
		}

		_ => {
			debug!("unknown action: {}", req.action);
			Err(anyhow::anyhow!("{}", DISCARD_MESSAGE_ERROR))
		}
	}
}	
	
```

We use the **http** request function to handle user events because in the current version of the TEA Party, the front-end sends the back-end http requests.

Similar to `handle_adapter_http_request`, we still have `handle_adapter_request` which is an upper level handler. That's because all http requests are actually captured by the [adapter](/z_glossary/adapter) first. Adapter is the sole component that a hosting CML can contact the outside world.

### libp2p\_back\_message

Tea project uses a modified version of rust-based lib P2P protocol between nodes communication.

The [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) use `libp2p_back_message` to handle libP2P messages. In our Tea party sample code, the only usage of this function is to receive response message to its own memory cache `help::set_mem_cache(&body.uuid, content)?;`.

The memory cache is used to temporarily store the response/error message from the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md). When the [front\_end](/z_glossary/front_end) sends a query for the result of any command, the hosting CML's back end actor will check this temporary store to get recently received results and get back to the [front\_end](/z_glossary/front_end).

### Interaction with OrbitDB

Query OrbitDb example: load\_message\_list

Please take a look at the function `pub fn load_message_list(req: &LoadMessageRequest) -> anyhow::Result<Vec<u8>>` in message.rs file

Focus on these lines:

```
	let dbname = db_name(req.tapp_id, &req.channel);
	let get_message_data = orbitdb::GetMessageRequest {
		tapp_id: req.tapp_id,
		dbname,
		sender: match req.address.is_empty() {
			true => "".to_string(),
			false => req.address.to_string(),
		},
		utc: block - 2,
	};

	let res = orbitdb::OrbitBbsResponse::decode(
		untyped::default()
			.call(
				tea_codec::ORBITDB_CAPABILITY_ID,
				"bbs_GetMessage",
				encode_protobuf(get_message_data)?,
			)
			.map_err(|e| anyhow::anyhow!("{}", e))?
			.as_slice(),
	)?;
	
```

First, generate the dbname which will be used later in the parameter `get_message_data` of the future provider call `bbs_GetMessage`.

The main function call is the provider call. `tea_codec::ORBITDB_CAPABILITY_ID` is the ID of the OrbitDB [provider](/z_glossary/provider). the `bbs_GetMessage` is the API name to call. The parameter needs to `encode_protobuf` so that the provider can decode it later. The response of this provider function call is a bytes buffer, so we have to issue `orbitdb::OrbitBbsResponse::decode` to a regular `res` data structure.

These lines are the typical way to call a provider. You can find such patterns everywhere in the TEA Project.

The rest of the code is easy to understand. The data response from the OrbitDB provider goes to the message\_item list. This list is returned to the [front\_end](/z_glossary/front_end) caller. Finally, it shows in the UI in the browser.

## Interaction with State Machine

Usually there are two kinds of requests that need to be sent to the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) to handle. They're either [queries](/z_glossary/queries) or [commands](/z_glossary/commands).

### Command example: post\_message

The function `post_message` sends a txn (we sometimes call it sending [Commands](/z_glossary/commands)) to the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md). The following code sends the txn:

```
	send_txn(
		"post_message",
		&uuid,
		bincode::serialize(req)?,
		txn_bytes,
		&tea_codec::ACTOR_PUBKEY_PARTY_CONTRACT.to_string(),
	)?;
```

In this function call, `"post_message"` is the name of the API that [state\_machine\_actor](/z_glossary/state_machine_actor) can handle. `uuid` is the nonce that the back-end actor uses to check the execution result. `txn_bytes` is the body of txn.

Let's follow the send\_txn code in request.rs:

```
pub fn send_txn(
	action_name: &str,
	uuid: &str,
	req_bytes: Vec<u8>,
	txn_bytes: Vec<u8>,
	txn_target: &str,
) -> anyhow::Result<()> {
	let ori_uuid = str::replace(&uuid, "txn_", "");
	let action_key = uuid_cb_key(&ori_uuid, "action_name");
	let req_key = uuid_cb_key(&ori_uuid, "action_req");
	help::set_mem_cache(&action_key, bincode::serialize(&action_name)?)?;
	help::set_mem_cache(&req_key, req_bytes.clone())?;

	info!(
		"start to send txn request for {} with uuid [{}]",
		&action_name, &uuid
	);
	p2p_send_txn(txn_bytes, uuid.to_string(), txn_target.to_string())?;
	info!("finish to send txn request...");

	Ok(())
}
```

If we keep following the call stack we'll eventually find more interesting details but we have to stop here. Otherwise, this article would become very long.

The remaining logic would be described as follows:

* Check the layer one, find the currently active state machine replicas, and their p2p addresses
* Randomly select 2 (or more if you think necessary) [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)s. Send the txn in P2P message to them.
* After the first txn P2P messages are sent out, record the time from the GPS atomic clock.
* Use this time stamp in the [followup](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/followup.md) message in the Ts field. Note, we only need the first txn's sent time, ignore the 2nd txn sent time.
* Send out the [followup](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/followup.md) message to those two [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)s (function `pub fn send_followup_via_p2p(fu: Followup, uuid: String)`).

### Query example: query\_balance

This function checks the user balance they've topped up to their TEA Party app account. `"query_balance" => api::query_balance(&serde_json::from_slice(&req.payload)?),`

You can find the main function here in user.rs

```
pub fn query_balance(req: &HttpQueryBalanceRequest) -> anyhow::Result<Vec<u8>> {
	check_auth(&req.tapp_id, &req.address, &req.auth_b64)?;

	info!("begin to query tea balance");

	let auth_key = base64::decode(&req.auth_b64)?;
	let uuid = &req.uuid;
	let req = tappstore::TappQueryRequest {
		msg: Some(tappstore::tapp_query_request::Msg::TeaBalanceRequest(
			tappstore::TeaBalanceRequest {
				account: req.address.to_string(),
				token_id: req.tapp_id,
				auth_key,
			},
		)),
	};

	send_query(
		encode_protobuf(req)?,
		uuid,
		tea_codec::ACTOR_PUBKEY_TAPPSTORE.into(),
	)?;

	Ok(b"ok".to_vec())
}
```

Finally the function call to send the P2P message is here inside p2p\_send.rs:

```
pub fn p2p_send_query(
	query_bytes: Vec<u8>,
	uuid: &str,
	to_actor_name: String,
) -> anyhow::Result<()> {
	let serial = QuerySerial {
		actor_name: to_actor_name.clone(),
		bytes: query_bytes,
	};
	let payload = encode_protobuf(tokenstate::StateReceiverMessage {
		uuid: uuid.to_string(),
		msg: Some(tokenstate::state_receiver_message::Msg::StateQuery(
			tokenstate::StateQuery {
				data: bincode::serialize(&serial)?,
				target: to_actor_name,
			},
		)),
	})?;
	info!("query payload => {:?}", payload);

	p2p_send_to_receive_actor(payload)?;

	Ok(())
}
```

You can follow how the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) finds the [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md) nodes and sends out using the p2p\_send\_to\_receive\_actor function:

```
fn p2p_send_to_receive_actor(msg: Vec<u8>) -> anyhow::Result<()> {
	let a_nodes = get_all_active_a_nodes()?;

	info!("all A nodes => {:?}", a_nodes);

	let mut len: usize = a_nodes.len();
	if a_nodes.len() < 1 {
		return Err(anyhow::anyhow!("{}", "No active A nodes."));
	} else if a_nodes.len() == 1 {
		warn!("Only 1 node to send, not safe.");
	} else if a_nodes.len() >= AT_LEAST_A_NODES_TO_SEND {
		info!(
			"Enough node to send. global => {}, require => {}",
			a_nodes.len(),
			AT_LEAST_A_NODES_TO_SEND
		);
		len = AT_LEAST_A_NODES_TO_SEND;
	}

	for node in &a_nodes[..len] {
		let target_conn_id = conn_id_by_tea_id(node.clone())?;
		info!("target conn id => {:?}", target_conn_id);

		let target_key = tea_codec::ACTOR_PUBKEY_STATE_RECEIVER.to_string();
		let target_type = libp2p::TargetType::Actor as i32;

		info!("p2p send msg start...");
		actor_libp2p::send_message(
			target_conn_id,
			libp2p::RuntimeAddress {
				target_key,
				target_type,
				target_action: "libp2p.state-receiver".to_string(),
			},
			None,
			msg.clone(),
		)?;
	}

	info!("p2p send msg finish...");

	Ok(())
}
```

The `a_nodes` is the internal name for [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md). `target_conn_id` is the address that libp2p can use to find the destination nodes.

### Query response after request

You may have noticed that no matter if it's [Commands](/z_glossary/commands) or [queries](/z_glossary/queries), the caller will not get the response immediately (even for [Queries](/z_glossary/queries) that are not supposed to have to wait in the [Conveyor](/z_glossary/conveyor). That's because all communication between nodes are asyncronous. However, you can always query the result using the `uuid` when you generate the request.

The front-end can use http `query_result` to get the result.

```

		"query_result" => {
			let req: HttpQueryResultWithUuid = serde_json::from_slice(&req.payload)?;
			let res_val = api::query_result(&req)?;
			Ok(serde_json::to_vec(&res_val)?)
		}

```

Please note, the front-end has no way to know when the result will be ready. It's common that the front-end needs to query several times to get the result. You can find the sample of how to query the result in the [front\_end](/z_glossary/front_end) code. In `bbs.js`, the function is `const sync_request = async (method, param, message_cb, sp_method='query_result', sp_uuid=null)`.


# party-fe

## Party-fe

The code is located at <https://github.com/tearust/tapp-sample-teaparty/tree/demo-code/party-fe>. You can clone the code to a local repo to make it easier to go through.

This is a standard Vue application. We assume that readers are familar with VUE and front-end web technologies. Below we'll only focus on the TEA related parts.

## bbs.vue common requests functions

This file <https://github.com/tearust/tapp-sample-teaparty/blob/demo-code/party-fe/src/views/bbs.js> handles most message-related user interactions.

For example, the code snippets below are handling a load message and send message request:

```
async loadMessageList(address, channel=default_channel){
    // F.top_log("Query message list...");
    const rs = await _axios.post('/tapp/loadMessageList', {
      tappId: F.getTappId(),
      channel: F.getChannel(channel),
      address: '',
    });

    // F.top_log(null);

    if(!rs) return [];

    return F.formatMessageList(JSON.parse(rs));

  },
  async updateTappProfile(address){
    const user = F.getUser(address);
    if(!user || !user.isLogin){
      throw 'not_login';
    }
    // TODO if user is not owner, return;

    const opts = {
      tappId: F.getTappId(),
      address,
      authB64: user.session_key,
      postMessageFee: 100,
    };
    const rs = await sync_request('updateTappProfile', opts);
    console.log('updateTappProfile => ', rs);
    return rs;
  },
  async sendMessage(address, msg, channel=default_channel, ttl=null){
    const user = F.getUser(address);
    if(!user || !user.isLogin){
      throw 'Not login';
    }
    
    msg = utils.forge.util.encodeUtf8(msg);
    const encrypted_message = utils.forge.util.encode64(msg);
    // console.log(121, utils.crypto.encode(address, msg));
    
    // const decode_msg = utils.crypto.decode(address, utils.forge.util.decode64(encrypted_message));
    // console.log('decode_msg => '+decode_msg);

    const opts = {
      tappId: F.getTappId(),
      address,
      channel: F.getChannel(channel),
      // message: msg
      encryptedMessage: encrypted_message,
      authB64: user.session_key,
      ttl,
    };
console.log('message => ', opts)
    let rs = null;
    if(opts.channel === 'test'){
      // free msg
      rs = await _axios.post('/tapp/postFreeMessage', {
        ...opts,
        uuid: uuid(),
      });
    }
    else{
      const txn = require('./txn').default;
      rs = await txn.txn_request('postMessage', opts);
    }
    
    return rs;
  },
```

You probably have noiticed that the most improtant line related to TEA is the line `await _axios.post('/tapp/loadMessageList'` for querying mesages, and this line \`await txn.txn\_request('postMessage', opts); for posting message.

You might have noticed that this line `await _axios.post('/tapp/postFreeMessage',` also looks like it's sending a command, but why is it not using `txn.txn_request()`? Well, posting a message does look like a command, but the free message doesn't cost anything. Therefore there is no state change (no money transfer). It can be comfortably handled by the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) alone without notifying the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md). No matter if it's [queries](/z_glossary/queries) or [commands](/z_glossary/commands), they are concepts related to the state machine and not your application.

### txn\_request

the `_axios.post` is a standard http call which doesn't need to be explained. We can focus on the txn.txn\_request utility function.

The code is under views/txn.js. Almost the entire file is comprised of this function.

```
import {_, axios, moment, uuid} from 'tearust_utils';
import utils from '../tea/utils';
import bbs from './bbs';

const F = {

  async txn_request(method, param){
    const _uuid = uuid();
    console.log("prepare for txn: ", method, _uuid);
    
    const _axios = bbs.getAxios();

    const txn_uuid = 'txn_'+_uuid;
    try{
      bbs.log("Send txn request...");
      console.log("Send txn request...");
      const step1_rs = await _axios.post('/tapp/'+method, {
        ...param,
        uuid: txn_uuid,
      });
      console.log("step_1 result: ", step1_rs);
    }catch(e){
      console.error("step_1 error: ", e);

      throw e;
    }

    bbs.log('Wait for query txn hash...');
    console.log('Wait for query txn hash...');
    await utils.sleep(5000);

    let step_2_rs = null;
    const step_2_loop = async ()=>{
      try{
        console.log('query result for '+txn_uuid+'...');
        step_2_rs = await _axios.post('/tapp/query_result', {
          uuid: txn_uuid,
        });

        step_2_rs = utils.parseJSON(step_2_rs);
      }catch(e){
        console.log("step2 error: ", e);
        // rs = e.message;
        step_2_rs = null;
        await utils.sleep(3000);
        await step_2_loop();
      }
  
    };
  
    bbs.log("Start to query txn result...");
    console.log("Start to query txn result...");
    await step_2_loop();

    console.log("step2 result: ", step_2_rs);

    bbs.log('Wait for next step...');
    console.log('Wait for next step...');
    utils.sleep(5000);

    const step_3_hash = step_2_rs.hash;
    const hash_uuid = "hash_"+_uuid;
    let step_3_rs = null;
    let step_4_rs = null;
    let sn = 0;
    const step_4_loop = async ()=>{
      if(sn > 10) {
        step_4_rs = {
          'status': false,
          'error': 'request timeout',
        };
        return;
      }
      try{
        bbs.log("Send query txn hash request...");
        console.log('Send query txn hash request...');
        step_3_rs = await _axios.post('/tapp/queryHashResult', {
          hash: step_3_hash,
          uuid: hash_uuid,
        });
    
        bbs.log('Wait for query txn hash result...');
        console.log('Wait for query txn hash result...');
        await utils.sleep(5000);

        console.log('query hash result for '+hash_uuid+'...');
        step_4_rs = await _axios.post('/tapp/query_result', {
          uuid: hash_uuid,
        });

        step_4_rs = utils.parseJSON(step_4_rs);
        if(!step_4_rs.status) throw step_4_rs.error;
      }catch(e){
        console.log("step4 error: ", e);

        if(e !== 'wait'){
          throw e;
        }
        
        // rs = e.message;
        step_4_rs = null;
        sn++;
        await utils.sleep(5000);
        await step_4_loop();
      }
  
    };
  
    bbs.log("Start to query hash result...");
    console.log("Start to query hash result...");
    await step_4_loop();

    console.log("step4 result: ", step_4_rs);
    if(step_4_rs.error){
      throw step_4_rs.error;
    }

    if(!step_4_rs.need_query){
      return step_4_rs;
    }

    // continue query

    let step_5_rs = null;
    let step_5_uuid = step_4_rs.query_uuid || _uuid;
    let step_5_n = 0;
    const step_5_loop = async ()=>{
      if(step_5_n > 3){
        throw 'query timeout...';
      }
      try{
        console.log('continue query for '+step_5_uuid+'...');
        step_5_rs = await _axios.post('/tapp/query_result', {
          uuid: step_5_uuid,
        });

        step_5_rs = utils.parseJSON(step_5_rs);
      }catch(e){
        console.log("step5 error: ", e);
        step_5_n ++;
        step_5_rs = null;
        await utils.sleep(5000);
        await step_5_loop();
      }
    };

    bbs.log("Start to query action result...");
    console.log("Start to query action result...");
    await step_5_loop();
    console.log("step5 result: ", step_5_rs);

    const rs = step_5_rs;

    return rs;
  }

};


export default F;
```

This is a big function, so let's dig into it step by step.

## uuid

Before the first step, we generate a UUID. This is used for a future results query (ecause all txns are async calls). You're not supposed to get a response immediately. You have to query after a period of time, and then from time to time until you get the result: either success or fail. UUID is the handle for such queries.

Once the UUID is confirmed, it uses an http call to the [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) like this:

```
const step1_rs = await _axios.post('/tapp/'+method, {
        ...param,
        uuid: txn_uuid,
      });
```

The [hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md) will handle this txn and run the back-end logic accordingly. If you are interested in that part, go to [back\_end\_actor](/z_glossary/back_end_actor).

## txn\_hash

The result from step1 doesn't mean anything. It just says "hey I accepted your txn request". In order to query the result of such a txn, we need to have the hash of that txn. We don't know it at this moment. The only thing we know is the UUID. So the step2 should query the txn\_hash using the UUID. You can see the code below:

```
let step_2_rs = null;
    const step_2_loop = async ()=>{
      try{
        console.log('query result for '+txn_uuid+'...');
        step_2_rs = await _axios.post('/tapp/query_result', {
          uuid: txn_uuid,
        });

        step_2_rs = utils.parseJSON(step_2_rs);
      }catch(e){
        console.log("step2 error: ", e);
        // rs = e.message;
        step_2_rs = null;
        await utils.sleep(3000);
        await step_2_loop();
      }
  
    };
```

The result of step2 is the txn\_hash. Now the front-end has the txn hash and the back-end has sent the txn to the [State\_Machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/t-rust/docs/_gitbook-dev-docs/1_core_docs/State_Machine.md). But we haven't got the result yet. In order to get the result, the front-end needs to ask the [back\_end\_actor](/z_glossary/back_end_actor) to initialize a series of [queries](https://github.com/tearust/t-rust/blob/master/docs/Sep2022_tokenomics/queries.md) to the [State\_Machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/t-rust/docs/_gitbook-dev-docs/1_core_docs/State_Machine.md) to get the result of the transaction. Step3 performs this "initialization" request.

```
step_3_rs = await _axios.post('/tapp/queryHashResult', {
          hash: step_3_hash,
          uuid: hash_uuid,
        });
    
```

Now, the [back\_end\_actor](/z_glossary/back_end_actor) receives the request and starts querying the [State\_Machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/t-rust/docs/_gitbook-dev-docs/1_core_docs/State_Machine.md) for the result. Because this is an async call, the back-end cannot get the result immediately. It will keep polling several times to get the result. When the back-end receives the result, it will cache it in memory for a short period of time, waiting for the [front\_end](https://github.com/tearust/t-rust/blob/master/docs/Sep2022_tokenomics/front_end.md) to fetch it. Step4 actually did the "fetching" job.

```
step_4_rs = await _axios.post('/tapp/query_result', {
          uuid: hash_uuid,
        });

        step_4_rs = utils.parseJSON(step_4_rs);
        if(!step_4_rs.status) throw step_4_rs.error;
      }catch(e){
        console.log("step4 error: ", e);

        if(e !== 'wait'){
          throw e;
        }
        
```

There are a few meaningful parameters in the step\_ r\_rs result. For example, do I need to wait and query again? This happens if the [back\_end\_actor](/z_glossary/back_end_actor) has not received the result from the [State\_Machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/t-rust/docs/_gitbook-dev-docs/1_core_docs/State_Machine.md) yet.

For most txns, as long as step4 has received the answer, the whole process is done. But for some txns, there are some follow-up tasks after the result. This is what step5 is supposed to do.

```
let step_5_rs = null;
    let step_5_uuid = step_4_rs.query_uuid || _uuid;
    let step_5_n = 0;
    const step_5_loop = async ()=>{
      if(step_5_n > 3){
        throw 'query timeout...';
      }
      try{
        console.log('continue query for '+step_5_uuid+'...');
        step_5_rs = await _axios.post('/tapp/query_result', {
          uuid: step_5_uuid,
        });

        step_5_rs = utils.parseJSON(step_5_rs);
      }catch(e){
        console.log("step5 error: ", e);
        step_5_n ++;
        step_5_rs = null;
        await utils.sleep(5000);
        await step_5_loop();
      }
```

Now the whole txn workflow is completed.

## Workflow

To make the workflow clear and visual, let's draw a sequence diagram.

{% @mermaid/diagram content="sequenceDiagram\
autonumber
participant Front end
participant Back end
participant State machine receiver
participant State machine executor

Front end->>+Back end: Step1, send uuid and txn
Back end->>+State machine receiver: send txn and follow up\
Back end->>-Front end: response ok
State machine receiver->>-Back end: Got it with txn hash
Front end->>+Back end: Step2, query txn hash using uuid
Back end->>-Front end: response txn hash
State machine receiver->>+State machine executor: sometime later, popup from conveyor and execute
Front end->>+Back end: Step3, Initialize result query
Back end->>-Front end: ok
State machine executor->>-State machine receiver: Executed, result is...
Back end->>+State machine receiver: Query result
State machine receiver->>-Back end: Response result. Back end store in cache. If result is not ready, ask to query later again.
Front end->>+Back end: Step4, Query result
Back end->>-Front end: Response result. if not ready, ask to query again later.
Front end->>+Back end: Optional step5, follow up tasks...
Back end->>-Front end: Ok..." %}


# Party-state-actor

This actor is loaded into the [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)'s [mini-runtime](/z_glossary/mini-runtime). It is the same concept as stored procedure in traditional cloud computing webapp. There are many pure functions that handle incoming txns and modify the state (including [state](/z_glossary/state) and [gluesql](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/gluesql.md) data).

As you already know, every [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md) runs an instance of this actor. All of them run the same txn at the same sequence and modify the same state to finally get the same new state. This is guaranteed by the [proof of time](/z_glossary/consensus#proof-of-time) consensus. As an application developer, you don't need to care too much about how it works. You can simply assume there's only one instance of your function running that updates a single state.

There are two types of requests: [queries](/z_glossary/queries) and [commands](/z_glossary/commands). Please click the links to get to know more about them. At least you should know that queries execute immediately, but commands need to wait a period of time prior to execution.

## Handling txns

Please go to [lib.rs](https://github.com/tearust/tapp-sample-teaparty/blob/demo-code/party-state-actor/src/lib.rs) and find the function\
fn txn\_exec\_inner(tsid: Tsid, txn\_bytes: &\[u8]) -> HandlerResult<()>. This is where most of the logic lives.

```
let (context_bytes, auth_key): (Vec<u8>, AuthKey) = match sample_txn {
		/// PostMessage, when user post a new message
		TeapartyTxn::PostMessage {
			token_id,
			from,
			ttl,
			auth_b64,
		} => {
			info!("PostMessage => from ttl: {:?},{:?}", &from, &ttl);
			let amt = calculate_fee(ttl);
			let auth_key: AuthKey = bincode::deserialize(&base64::decode(auth_b64)?)?;
			let auth_ops_bytes = actor_statemachine::query_auth_ops_bytes(auth_key)?;
			let ctx = TokenContext::new(tsid, base, token_id, &auth_ops_bytes)?;
			let req = ConsumeFromAccountRequest {
				ctx: bincode::serialize(&ctx)?,
				acct: bincode::serialize(&from)?,
				amt: bincode::serialize(&amt)?,
			};
			(actor_statemachine::consume_from_account(req)?, auth_key)
		}
```

The code above shows how you handle the PostMessage txn.

This txn (sometimes we call it a command) is generated in the [party-actor](/z_glossary/party-actor) when user click post message button in [party-fe](/z_glossary/party-fe).

The message has been stored to the [orbitdb](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/orbitdb.md) by [back\_end\_actor](/z_glossary/back_end_actor), the only thing this actor is supposed to do in the state level is to transfer the gas fee. Gas fee is what the end users supposed to pay for this kind of service, in this case, posting a message.

In this function, the logic determines how much (amt) the user need to pay based on the TTL (time to live), and who should pay (the message sender). Finally, call the `actor_statemachine::consume_from_account` function.

There are a few concepts we'll need to explain here. [authKey](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/authKey.md) and [context](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/context.md). Please click the links for further explanation.

There are other txns this function handles. They are very straightforward from just reading the txn name and code.

## Commit state changes

After the txn has been handled, all changes are not commited yet. they are just saved to [context](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/context.md). So you can see the code after all the txns ahave been handled. This code is used to commit the changes.

```
if context_bytes.is_empty() {
		error!("######### party state actor txn handle returns empty ctx. Cannot commit ######");
		return Ok(());
	}
	let hidden_acct_balance_change_after_commit = actor_statemachine::commit(CommitRequest {
		ctx: context_bytes,
		auth_key: bincode::serialize(&auth_key)?,
	})?;
	if hidden_acct_balance_change_after_commit != (0, 0) {
		warn!("********* party state actor commit succesfully but the hidden account balance changed. make sure a follow up tx is trigger to keey the balance sheet balance. {:?}", &hidden_acct_balance_change_after_commit);
	} else {
		info!("*********  party state actor commit succesfully.");
	}
	Ok(())
}
fn health(_req: codec::core::HealthRequest) -> HandlerResult<()> {
	info!("health call from party-state actor");
	Ok(())
```

The hidden balance is used to verify if the txn made any mistake that caused the state to be unbalanced after the update. If all the code is correct, there shouldn't be any unbalanced state.

After the commit, the state is finally changed. Before the commit, any error causing the function to return early will not affect the state. The state remains as it was before. See [context](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/context.md) for more details about atomic transaction concepts.


# Providers

Providers are static utility libraries inside of the [mini-runtime](/z_glossary/mini-runtime). The providers are called by the [actors](/z_glossary/actor) inside the [mini-runtime](/z_glossary/mini-runtime). Actors are WebAssembly code that can only run inside the Wasm virtual machine. But providers are native rust code that can run outside of the virtual machine. If you read the [magic\_of\_wasm](/z_glossary/magic_of_wasm) document, you'll know that WebAssembly is a very secure execution format that can run inside the Wasm virtual machine. On the other hand, running inside a virtual machine means it cannot call system functions directly. Assuming you're writing a Solidity smart contract, you'll know that you cannot call the OS API directly because the smart contract will be running inside the EVM.

What if the actor code wants to call an OS function to send data over the network or to save a number to the [state](/z_glossary/state)? That's when providers can step in to help.

## Providers security concern

There are many providers inside the [mini-runtime](/z_glossary/mini-runtime). These providers are all writen by the TEA Project core team at the moment. Because provider code is native code that runs with OS privileges, it's much more powerful than the code inside of actors. Powerful also means more damage if abused. Actors' code cannot do too much damage because of its isolation and the limitations imposed by the virtual machine. But if the actor code call provider code, the actor can make big damage if misused. In order to mitigate this threat:

* For every type of system function, we developed a separate provider.
* The actor's developer needs to choose and sign which providers it will use. This is also called [capability](/z_glossary/capability).
* The capability information is stored as public data. If an actor is not supposed to use a provider but claimed it will, the DAO or end-user will reject this application from executing.
* All provider code is carefully designed and audited.

## Calling providers

All functions inside of providers are pure functional functions. That means they are **stateless**. The caller (from the actor) needs to send all necessary parameters with the function and will get the result (bytes) in the return value.

Every function has an OP\_CODE. All input values and output values are Protobuf encoded. In most cases, the actor call to the provider is happening inside of the same encalve. There's no need for encryption and all calls are synced call.

## Error handling

TODO:


# Public Service

Unlike other blockchain projects that waste lots of computing power in consensus competitions, the TEA project uses all of its computing power in useful tasks. The majority of them are commercial task which are, of course, paid by the clients benefitting from running them. A minority of them are public validation or DAO governance taks. These proportionally small number of tasks are not paid out by any specific client. Rather, they would have to be paid by the DAO as these are public services.

Public services include:

* [Remote attestation](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/remote_attestation.md) (this is similar to jury duty in real life).
* State machine maintenance (similar to goverment expenses).
* DAO governance (similar to elections / voting in real life).
* Other tasks that are necessary and benefit the public.

The DAO will pay these public services from TEA token inflation. There are a fixed number of TEA tokens minted in every block, which are paid to the miners who executed the public services in the block. The actual block reward number may change over time but will be predictable.

The block reward inflation will be hedged by TEA burning as a consequence of [CML\_auctions](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/cml_auction.md).


# queries

## Queries

Query is a "read-only" inquiry to read a state value from the state machine.

Because TEA state machine nodes are consistent with each other (i.e. they have **strong consistency**), the hosting node can access any other state machine node to query information. The result would be the same.

There's no wait time associated with queries. The state machine can always check its current state and respond back to the hosting node.

![8](https://user-images.githubusercontent.com/86096370/159343556-a4fc7d94-7630-4d04-be50-4e9ce704ed0f.png)

## Tsid in the response

Although the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) exhibits **strong consistency**, there might be a slight delay across [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)s. Because of this possible delay, when you query a particular replica, you may get the state that's differs from the **most recent state**.

For example, when you query the TEA Party token price **now** to two different [state machine replicas](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md), the replica A just completed a txn marked (tsid as) at 1000. It will respond to you with the TEA party token price at the time of 1000. But replica B may be a little laggy, that it only processed the txn marked (tsid is) at 999. So it will respond to you with the price at the time of 999 instead of 1000. If there is a change between timestamp 999 and 1000, you may get two different prices.

To indicate this specifically, every time the state machine responds with a value, it will attach a timestamp, meaning that the vlaue is valid as of that timestamp.

The caller ([hosting\_cml](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/hosting_cml.md)) can determine is the tsid is too old or not. It can then decide to query again or accept it as is.


# Remote Attestation

Remote attestation is one of the most important concepts of **Trusted Computing**, it's also the cornerstone of the TEA Project.

If we send a bunch of code and data to a computer, how do we know the computer is doing what it's supposed to be doing and that the result is trustable? As a human, we only can see the outside of a machine but have no way of figuring out what real firmware software is running inside. What if a hacker has modified the firmware or software inside the machine? The computer will look exactly the same as it was before the breach.

Trusted computing was invented to solve this problem. The computer itself can detect the integrity (for example, **secured boot**) or detect another computer's integrity (this is called **remote attestation**).

Validation of integrity is basically comapring the hash of a hardware/firmware/software stack with a series of known correct hash values. If any of these values changes and no longer matches what they're supposed to be, the remote attestatation has failed. Those verifable hash values are provided by the [tpm](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/tpm.md) security chips.

The attestors are selected randomly by the layer1 blockchain. This is out of human control. Every individual attestor made its own decision seperately, and the result was sent to layer1. Layer1 smart contracts runs a BFT algorithm to determine if a candidate is trustable or not. The attestors and layer1 works as members of jury duty and judge the node under inspection.

The details of Trusted Computing and Remote Attestation are beyond the coverage of this document. But these are very important topics wort reahding more about.

For a quick overview of Trusted Computing please go to this [Stanford page](https://cs.stanford.edu/people/eroberts/cs201/projects/trusted-computing/what.html). For more details visit [the trusted computing group](https://trustedcomputinggroup.org/) as well as [Microsoft's explanation of TPM key attestation](https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/tpm-key-attestation).


# Staking to Hosting CML

Staking to a hosting CML mining node is a way for users to earn a share of mining revenue without having to setup a mining machine. Each active hosting CML mining machine will have its own stake token associated with it. Owning a miner's stake token entitles the holder to earn a percentage of that miner's revenue.

* CML miners earn the gas fee paid by the end-user to use their hosting infrastructure to run TApps.
* CML miners also earn a public service reward as well as any surpluses above their public service reward payout from the Harberger Tax paid by the state maintainers.

In addition to earning dividends, hosting CML token holders will also benefit from the price appreciation of the token itself. Mining stake tokens are issued on a bonding curve, which means that the price of the token increases as the supply increases.

* As TEA mining rewards are earned, the net percentage after the miner gets their allotted (theta %) share is injected into the bonding curve. This results in an increase in the number of mining stake tokens which are distributed proportionally as a dividend to existing staking token holders.
* As TApp token mining rewards are earned, the net percentage after the miner takes their share is distributed proportionally as a dividend to existing staking token holders. Note that because no TEA is being injected into the mining stake token bonding curve during TApp token distributions, this event doesn't change the supply or price of staking tokens as it does when TEA is distributed to staking token holders.

## Revenue split between miners and mining stake token holders

`#########` **TODO** The following section is speculative:

* What is the split between miners and token holders?
* Is the portion that goes directly to the miners considered theta just like in the TApps (and thus will be the difference between the buy and sell curves of the mining stake token bonding curve) `#########`

All mining revenue will be split between the miner and mining stake token holders as follows:

* 50% will go to the miner.
* 50% will go to the staking token holders. Note that the staking token holder group also includes the miner who will own some of the mining stake tokens.

## Private CML don't have stake tokens

Private CML are the CML that users deploy to their home TEA boxes to allow them to run on the TEA network. Because these machines don't allow random end-users to utilize their hardware, these miners currently only earn Availability Attestation rewards. Availability attestation is a service private CML provide which allows them to be online or offline as they wish. This is compared to the much more stringent requirements to be a hosting CML mining node that must always be online to host TApps or else suffer penalties. Because private CML machines aren't always online, they only earn direct fees from providing an ancillary service to the network. Because these private CML are not actively providing hosting services to TApps, there's no consume function revenue to share with stakers.


# Staking to TApp

Each TApp has a token associated with it that's issued along a bonding curve, and buying a TApp's token is just like staking to it. Using TEA to "stake" to a TApp is just like owning stock in a TApp. When a user stakes their TEA in a TApp in return for its TApp token, they can then earn financial benefits in a couple of ways:

1. The TApp token itself is issued along a bonding curve. As supply increases, the price increases with it.
2. As consumers use the TApp, a consume action injects TEA into a TApp, only some of which goes to the developer. The rest of the TEA is exchanged for the TApp's tokens and then distributed proportionally to the TApp token holders.

TApp tokens play an important role in the TEA Project ecosystem as it helps developers bootstrap their projects by enticing investors and other interested users to purchase its TApp token in the hopes of price appreciation (with the developer getting a share of every purchase).

## Bonding curve mechanism

When we say that TApp tokens are issued along a bonding curve, that gives a mathematical formula correlating the total TApp token supply and its price, e.g. **price = sqrt(supply)**.

![Bonding-Curve](https://user-images.githubusercontent.com/86096370/167538641-45c498a2-7ab1-428a-9ecd-b37a051bb9d2.png)

You'll notice in the graph above that there are two curves which determine a buy and a sell price. The difference between these two curves comes from the value of **theta**, which is the percentage of every bonding curve augmentation (increase) that goes directly to the developer. Theta can be thought of as the amount of every token purchase or consume action that goes to the TApp developer. Someone who buys a TApp token and then immediately sells it will only get (1-theta) \* (TEA amount they used to purchase TApp tokens), which is exactly what the two curves are depicting.

It's important to note that while the buy curve is hypothetically what one would pay if they were to purchase a TApp token, the sell curve shows you exactly how much TEA is underlying one TApp token at that supply level. This means that the TEA really is locked in the bonding curve, and selling TApp tokens into a bonding curve essentially releases the underlying TEA while burning the supply of the TApp token. The sell action will also lower the TApp token price along the bonding curve. Mathematically, the sell price is always (1 - theta) \* (buy price) anywhere along the bonding curve.

## Consume action

Each time a TApp is used it initiates a consume action. The developer gets their share (**theta**) of the TEA entering the bonding curve, and the rest of the consume revenue is converted to TApp tokens and distributed proportionally to TApp token holders. This is considered the dividend reward for being a TApp token holder.

Because consume actions introduce a new supply of TApp tokens minted along the bonding curve, this means that not only will TApp token holders earn dividends, their token values will also go up at the same time.

## Developers are paid from the bonding curve, not directly from consumers

Although it might make sense to think that a developer gets paid when consumers use their TApp, that's not technically correct. The developers aren't technically paid until the TEA enters the TApp token bonding curve through either consumers using the TApp or investors purchasing its token. You can say that developers are rewarded for both the utility their app brings to consumers and for any bullishness in the eyes of investors.

Developers always gets their **theta** percentage share anytime TEA tokens enter the bonding curve. Let's take a look at the two scenarios where money enters the bonding curve:

#### 1. If an investor purchases TApp tokens,

* theta (%) of the purchase amount goes to the developer.
* the rest of the TEA goes to mint TApp tokens which go to the wallet of the user who purchased the TApp token.

#### 2. If a consumer uses the TApp

* theta (%) of the TEA the consumer uses goes to the developer.
* The new tokens generated by this injection of TEA doesn't go to the consumer of the TApp - they already got the TApp's utility since that's what they paid for. But TEA is being injected into the bonding curve which creates new TApp tokens, and these tokens have to go somewhere. These newly minted TApp tokens are distributed proportionally as dividends to existing TApp token holders.


# State

[Wikipedia](https://en.wikipedia.org/wiki/State_\(computer_science\)) defines state as the following:

> In [information technology](https://en.wikipedia.org/wiki/Information_technology) and [computer science](https://en.wikipedia.org/wiki/Computer_science), a system is described as **stateful** if it is designed to remember preceding events or user interactions; the remembered information is called the **state** of the system.

In a traditional cloud computing architecture, the database is most likely used as state storage. In the blockchain world, the whole blockchain is a giant distributed state machine. For example, Ethereum itself is a state machine. Everytime clients send transactions to update the state, every new block means a new updated state is released.

In the TEA Project, we don't store the application state in the blockchain. Instead, the state is stored in a group of [state\_machine\_replica](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md)s. We use a new [Proof of Time](/z_glossary/consensus#proof-of-time) hardware consensus to achieve super fast speed (relative to traditional blockchain) and processing power without sacrificing security or scalability.

Please keep reading the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) and [consensus](/z_glossary/consensus) for more details.


# State Machine

## How TEA Handles State Changes

In a typical blockchain, the default status of nodes in the network is untrusted. This lack of trust ends up being an expensive design decision for traditional blockchains. In blockchains like Bitcoin and Ethereum where there's no trust among nodes, every node will need to reproduce all states since the beginning genesis block. So we can say that one consequence of traditional blockchains’ lack of trust is that the block size grows larger over time (as it needs to store all transactions that have ever occurred on the chain), which has an associated drag on transaction speed.

The TEA Project can quickly sync up its nodes through the trust built into its design. This conceptually is a major difference it has with traditional blockchains.

Because the onboard TPM chips of mining nodes allow attestation to be run on them, they can be guaranteed to be trustworthy and don’t need to sync up a historical ledger of all previous transactions. The TEA Project’s state machine only needs to store the resulting state change of transactions in RAM and not the transaction itself. Once all nodes are trustable, any node can get the latest state from a nearby node’s RAM. Syncing up to the latest state through reading a nearby node’s RAM is a quicker process than reconstructing the current state by recomputing and verifying the entire history from the very beginning.

In the TEA Project:

* Transactions are processed with the resulting state change stored in the RAM memory residing in the enclaves of the state machine mining nodes.
* Only state machine nodes run the strong consistency state machine (including the SQL database instance).
* Every state machine node will have the same copy of the state in its memory.

All new transactions are already ordered through our use of GPS satellites (Proof of Time). Time can be proven accurate as the TPM chip onboard our layer-2 mining nodes helps ensure that the GPS module’s timing hasn’t been altered. Most importantly, our strong consistency state machine that runs through state machine mining nodes doesn’t need any consensus as there are no new blocks to wait for. Instead of blocks, new transactions land on a [conveyor](/z_glossary/conveyor) belt, and eventually everyone ends up with the same state. The TEA Project’s state machine functions just like a decentralized database that developers can use.

There are major benefits to TEA’s state machine and how it uses time as a root of trust.

1. The TEA state machine updates continuously because there’s no block. There’s no need to wait every few seconds to get the consensus of all other nodes. All nodes have agreed on the time source from the atomic clock of GPS satellites.
2. A new node joining the network doesn’t need to sync up from the very beginning of the genesis block. It just loads the current state from any nearby trusted state machine. The trust comes from the hardware and blockchain (layer-1) certification, not from self-verification from the block history, which means that syncing takes almost no time.


# State Machine Actor

This actor is the TApp's actor that's loaded into the [mini-runtime](/z_glossary/mini-runtime) of the [state machine replicas](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine_replica.md). It handles the [txn](/z_glossary/txn) (also called command) to update the state.

Only the [txn](/z_glossary/txn) that's moved to the last execution point of the [conveyor](/z_glossary/conveyor) can be picked up and executed in this actor.


# State Machine Replica

[The state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) is the database tier that contains multiple replications. Every replication is a **State Machine Replica**.

Every replica is a standalone state machine CML node. It syncs with the other state machine CML nodes.

Our [Proof\_of\_Time](/z_glossary/consensus#proof-of-time) algorithm guarantees that all state machine replicas run all transactions (or any called commands) at the same sequence. As a result, the same state will be kept among all replicas.


# TEA ID

Every TPM ships with a unique asymmetric key, called the *Endorsement Key* (EK), burned by the manufacturer. We refer to the public portion of this key as *EKPub* and the associated private key as *EKPriv*. Some TPM chips also have an EK certificate that is issued by the manufacturer for the EKPub. We refer to this cert as *EKCert*. The **TEA ID** is the EKPub of TPM chip inside every TEA mining machine.

This ID cannot be modified or updated once the chip is built. The TEA machine manufacturor can register this TPM ID to our layer-1 blockchain. The registration process requires the TPM manufacturor's EKCert. Anyone can verify any TPM EKPub using such an EKCert.

For more detail please see [Microsoft's explanation of TPM key attestation](https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/tpm-key-attestation).


# TPM

The TPM is a popular security chip that exists in almost every computer and most phones. We rely on each node's TPM to generate Proof of Trust data that can undergo remote attestation by a verifier.

TPM is the main component of the Trusted Computing technology. Here's a good simulator to get some hands on experience with TPM: <https://google.github.io/tpm-js/>.

For a quick overview of Trusted Computing please go to this [Stanford page](https://cs.stanford.edu/people/eroberts/cs201/projects/trusted-computing/what.html) or for more detail visit [the trusted computing group](https://trustedcomputinggroup.org/).

For the reasons why we need TPM, you can read [about our consensus](/z_glossary/consensus).

Every node's [enclave](/z_glossary/enclave) is protected by a TPM chip, and the [mini-runtime](/z_glossary/mini-runtime) runs inside the [enclave](/z_glossary/enclave).


# Transactions

Transactions (txns) are also called [commands](/z_glossary/commands) or events.

A txn is generated by a [back\_end\_actor](/z_glossary/back_end_actor) or [blockchain\_listener](/z_glossary/blockchain_listener) and executed in a [state\_machine\_actor](/z_glossary/state_machine_actor) to update the [state](/z_glossary/state).

A txn is the only outside trigger that's able to change the [state](/z_glossary/state). In other words, all state changes are triggered by txn(s).

## Some examples of txns

Alice sends 10T to Bob. This is a transfer txn. Every 1000 blocks, we run a clean up of the blockchain storage. This is a [blockchain\_listener](/z_glossary/blockchain_listener) triggered txn. It looks like a cron job. If the blockchain notices a new TApp is created, then it performs a **generate tapp account** task. Although this is also a [blockchain\_listener](/z_glossary/blockchain_listener) triggered txn, it's not considered to be like a cron job.

## Binary successful or failed on execution

A txn can be successfully executed or failed. If it's successful, it may or may not change the state. But if it's failed, it will definitely **NOT** change the state.

There are **no partially successful txns**. They're either fully successful or totally failed.


# VMH - Virtual Messaging Hub

The VMH is a UDS (Unix Domain Socket) channel between the enclave and the outside parent instance. This is the only allowed information exchange tunnel.

According to the enclave security rule, all information that should be kept secret will need to be encrypted before being sent out of the enclave.

When sending message via the VMH, a destination component name is specified so that the corresponding component will receive the messages while other components won't.


# Where Messages are Stored

In the TEA Party, the messages are stored in an [OrbitDB](http://orbitdb.org) database. OrbitDB is a non-relational database running on top of IPFS.

## Security

For TEA Party's public messages, there's no need to encrypt.

Messages are stored in [orbitdb](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/orbitdb.md) (and eventually in IPFS) in plain text.

But private messages aren't saved in plain text. The hosting nodes will encrypt the message using the [app\_aes\_key](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/app_aes_key.md) and then save the cypher to OrbitDB.

Because only TEA Party hosting nodes have the [app\_aes\_key](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/app_aes_key.md) in their own enclave, other apps or users cannot get the content of these messages.

## Cost

OrbitDB /IPFS is very cheap compared to using the [state machine](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/state_machine.md) which exclusively uses RAM to store the state. For more details, please see [orbitdb](https://github.com/tearust/t-rust/blob/master/docs/_gitbook-dev-docs/z_glossary/orbitdb.md).


