Skip to content

Commit

Permalink
docs: update aetherlink
Browse files Browse the repository at this point in the history
  • Loading branch information
yongenaelf committed Sep 5, 2024
1 parent 999961d commit 63a95f1
Showing 1 changed file with 173 additions and 105 deletions.
278 changes: 173 additions & 105 deletions docs/resources/aetherLink/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,163 +4,231 @@ title: AetherLink
description: Transfer tamper-proof data from off-chain to on-chain
---

# AetherLink
## 1. Background

## 1. Introduction
There is a growing need for decentralized applications (dApps) to access data feeds that are frequently updated, reliable, and secure. AetherLink Oracles is a leading oracle provider directly fulfilling this need.

A web3 oracle is essential for decentralized networks, enabling smart contracts to access real-world data like weather
updates or market prices. However, the security of oracles is a concern, as malicious actions can compromise contract
execution. Choosing reliable oracle services is crucial in web3 development. Moreover, oracles not only link blockchains
to real-world data but also enable the retrieval of information from other blockchain networks.
## 2. Target

![oracle](/img/oracle.png)
For developers of the AELF ecosystem, this article will provide a complete guide to accessing the AetherLink **VRF** and **Datafeeds** contracts.

## 2. aelf Oracle Services - AetherLink
## 3. Operational

Among the various products in aelf, some products may require information from other chains. For example, the [eBridge](https://ebridge.exchange/)
product needs to access lock-up information of NFTs on the Ethereum chain. This necessitates the use of oracle services
for data interchange. To expand the aelf ecosystem and enhance user services, it is essential to establish the
foundational services for oracle mechanisms.
### 3.1 Preparation

In this context, AetherLink, aelf's proprietary oracle service, has been developed. AetherLink primarily focuses on
providing Verified Random Function (VRF) capabilities and Data Feeds functionality.
#### 3.1.1 Import proto

## 3. What can AetherLink do?
First, you need to import oracle-related proto files into your contract csproj file.

### A. Random number generator
```xml
<ItemGroup>
<CommonMessage Include="..\..\protobuf\oracle_common_message.proto">
<Link>Protobuf\Proto\oracle_common_message.proto</Link>
</CommonMessage>
</ItemGroup>
<ItemGroup>
<ContractReference Include="..\..\protobuf\oracle_contract.proto">
<Link>Protobuf\Proto\oracle_contract.proto</Link>
</ContractReference>
</ItemGroup>
<ItemGroup>
<ContractBase Include="..\..\protobuf\request_interface.proto">
<Link>Protobuf\Proto\request_interface.proto</Link>
</ContractBase>
</ItemGroup>
```

Generating random numbers directly on the blockchain is a complex and challenging problem. Due to the deterministic
nature of blockchain, the results of smart contract executions must be consistent across all nodes in the network.
Therefore, random number generation in smart contracts needs to be verifiable and replicable, ensuring that each node
obtains the same result when executing the same smart contract.
You can find the latest proto files through the following link:

However, traditional pseudo-random number generation methods, such as using block hashes, face challenges in this
environment. If block hashes are used, each node in the smart contract would generate the same random number using
identical inputs, making it impossible to achieve true randomness.
- https://github.com/AetherLinkProject/aetherLink-contracts/blob/master/protobuf/oracle_common_message.proto
- https://github.com/AetherLinkProject/aetherLink-contracts/blob/master/protobuf/oracle_contract.proto
- https://github.com/AetherLinkProject/aetherLink-contracts/blob/master/protobuf/request_interface.proto

AetherLink VRF introduces the concept of Verifiable Random Function (VRF), employing algorithms designed by
cryptographic experts to ensure that the generated random numbers on-chain are verifiable and unpredictable. AetherLink
VRF provides a secure, decentralized, and verifiable mechanism for generating random numbers in smart contracts,
delivering high-quality randomness without compromising security and usability.
#### 3.1.2 Protobuf file

The key advantages of using AetherLink VRF include:
Then you also need to introduce request_interface.proto in the proto file to inherit the oracle callback function to receive the oracle report

#### 1. Verifiability:
```protobuf
import "aelf/core.proto";
import "aelf/options.proto";
import "request_interface.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
Cryptographic proofs are used to demonstrate the authenticity of the random number generation process, allowing smart
contracts and users to verify the legitimacy of the generated random numbers.
service <YOUR CONTRACT NAME> {
...
#### 2. Unpredictability:
option (aelf.base) = "request_interface.proto";
Utilizing VRF algorithms ensures that random numbers generated by AetherLink VRF are unpredictable, even under identical
input conditions.
...
```

#### 3. Decentralization:
#### 3.1.3 Set Oracle Address

AetherLink VRF operates across multiple nodes, enhancing the decentralization of random number generation and mitigating
risks associated with a single point of control.
Set the Oracle Contract Address in your contract state according to your operating environment.

```csharp title="Random number generator code segment"
{
var random = State.ConsensusContract.GetRandomHash.Call(new Int64Value
{
Value = specificData.BlockNumber
});
- MainNet **AELF** Address : `BGhrBNTPcLccaxPv6hHJrn4CHHzeMovTsrkhFse5o2nwfvQyG`
- MainNet **tDVV** Address : `BGhrBNTPcLccaxPv6hHJrn4CHHzeMovTsrkhFse5o2nwfvQyG`
- TestNet **AELF** Address : `21Fh7yog1B741yioZhNAFbs3byJ97jvBmbGAPPZKZpHHog5aEg`
- TestNet **tDVW** Address : `21Fh7yog1B741yioZhNAFbs3byJ97jvBmbGAPPZKZpHHog5aEg`

var alpha = HashHelper.ConcatAndCompute(random, specificData.PreSeed);
#### 3.1.4 Apply subscription ID

Context.ECVrfVerify(publicKey, alpha.ToByteArray(), report.Result.ToByteArray(), out var beta);
Assert(beta != null && beta.Length > 0, "Vrf verification fail.");
Before initiating a task to the oracle, you need to contact AetherLink to apply for a subscription number for your task. Later, you can manage the service fee based on this subscription id.Remember that you only have the right to use your own `subscription id`.

var randomHash = Hash.LoadFromByteArray(beta);
:::note

for (var i = 0; i < specificData.NumWords; i++)
{
response.Data.Add(HashHelper.ConcatAndCompute(randomHash, HashHelper.ComputeFrom(i)));
}
If you have prepared all the above work, we will explain the VRF and Datafeeds scenarios separately. You need to choose the appropriate contract as the entry point for your development scenario

return response;
}
```
Currently, we provide two oracle capabilities:

- VRF: VRF provides cryptographically secure randomness for your blockchain-based applications.
- Datafeeds: Provide data sources for Web2 asset prices for contracts.

The process involves obtaining a random hash from the consensus contract, verifying it through ECVRF with a public key
and an oracle-reported result, and then creating a set of random words based on the verified data.
:::

### B. DataFeeds
### 3.2 DataFeeds

The AetherLink Data Feeds Coordinator provides a quick and reliable connection for smart contracts to real-world data,
encompassing data types like asset prices, reserve balances, NFT floor prices, and L2 sequencer health.
First, you need to define how to initiate a Datafeeds oracle request in the contract.

Data feeds from the Coordinator include Price Feeds, Proof of Reserve Feeds, NFT Floor Price Feeds, Rate and Volatility
Feeds, and L2 Sequencer Uptime Feeds. For example, Price Feeds are crucial for real-time actions in applications like
decentralized finance (DeFi) platforms. These feeds aggregate data from multiple sources, ensuring reliability through
the Decentralized Data Model and Offchain Reporting.
```csharp
State.OracleContract.SendRequest.Send(new SendRequestInput
{
SubscriptionId = SubscriptionId,
RequestTypeIndex = 1,
SpecificData = specificData,
TraceId = XXXXX // HASH
});
```

- `OracleContract`: This is the target contract address, the oracle contract.
- `SendRequest`: This is the method name for sending the Datafeeds Request to the target contract.
- `SendRequestInput`: This is the input parameter of the method for sending transactions to the target contract

| Param Name | Explanation | |
| ---------------- | ------------------------------------------------------------------ | --------------------------- |
| SubscriptionId | manage the service fee based on this subscription id | int32 |
| RequestTypeIndex | Task Type | int32, 1=Datafeeds \| 2=VRF |
| SpecificData | Detailed description of Datafeeds tasks | ByteString |
| TraceId | This ID can be used as a unique index to manage your oracle tasks. | Aelf.Hash |

Components of a data feed involve the Consumer (onchain or offchain applications using Data Feeds), Coordinator contract
(onchain coordinator pointing to the oracle), and Oracle contract (receiving periodic data updates from the oracle
network and storing aggregated data onchain).
#### 3.2.1 How to generate DataFeeds SpecificData

Different data feeds cater to specific use cases, such as Proof of Reserve Feeds indicating the status of reserves, NFT
Floor Price Feeds providing the lowest NFT prices, and Rate and Volatility Feeds offering interest rate curve data. L2
sequencer uptime feeds track the last known status of the sequencer on Layer 2 networks.
Here we take the example of collecting ELF-USTD currency price pairs every 10 minutes. Note the red part:

```json
{
"Cron": "0 */10 * * * ?",
"DataFeedsJobSpec": {
"Type": "PriceFeeds",
"CurrencyPair": "ELF/USDT"
}
}
```

## 4. AetherLink Contracts
After determining the task description, you need to convert it into a bystring type and then put it into the input parameter of the oracle request.

To achieve these functionalities, aelf has deployed 3 main contracts. Their names and their functionalities are:
```csharp
var jobSpec = "{\"Cron\": \"0 */10 * * * ?\",\"DataFeedsJobSpec\": {\"Type\": \"PriceFeeds\",\"CurrencyPair\": \"ELF/USDT\"}}";

| Contract Type | Functions and Responsibilities |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Consumer Contract | 1. Task initiation and receipt of results<br />2. Result inquiry |
| Coordinate Contract | 1. Task management<br />2. VRF Proof verification and random number generation<br />3. Threshold signature verification |
| Oracle Contract | 1. Node management<br />2. Task event publication |
var specificData = new AetherLink.Contracts.DataFeeds.Coordinator.SpecificData
{
Data = ByteString.CopyFromUtf8(jobSpec),
DataVersion = 0
}.ToByteString()

### A. Consumer Contract
var sendRequestInput = new SendRequestInput
{
SubscriptionId = 1,
RequestTypeIndex = 1,
SpecificData = specificData,
TraceId = HhfWg...Y9kao31 // HASH
}
```

A contract deployed by the user, for which the official interface proto file is provided by the platform for task
initiation and result retrieval. Users are required to reference and implement this interface. The main functionalities
include:
#### 3.2.2 How to handle oracle pricefeeds callbacks

#### a. Task initiation:
Here you need to override the HandleOracleFulfillment method

Initiated by the user, subsequently invoking the Oracle contract to carry out subsequent operations.
```csharp
public override Empty HandleOracleFulfillment(HandleOracleFulfillmentInput input)
{
...

#### b. Result retrieval:
var priceList = LongList.Parser.ParseFrom(input.Response);

Callback function executed by the Oracle contract, writing the results back to the user contract. Users are responsible
for implementing the logic for data storage.
var longList = new LongList { Data = { priceList.Data } };

### B. Coordinator Contract
var sortedList = longList.Data.ToList().OrderBy(l => l).ToList();

A contract provided by the platform. Based on the current products, PriceFeeds and VRF, two corresponding Coordinator
contracts need to be deployed. The main functionalities include:
var round = State.LatestRound.Value.Add(1);

#### a. Task management:
var newPriceRoundData = new PriceRoundData
{
Price = sortedList[sortedList.Count / 2],
RoundId = round,
UpdatedAt = Context.CurrentBlockTime
};
State.LatestPriceRoundData.Value = newPriceRoundData;
State.PriceRoundData[round] = newPriceRoundData;
State.LatestRound.Value = round;
}
```

Generates a unique 1D for tasks along with task details, storing them in the contract.
The above code will parse the oracle callback and record each result in the contract, providing the latest and historical currency price query capabilities.

#### b. Threshold signature verification (for non-algorithmic verification thresholds) / VRF Proof verification:
### 3.3 VRF

After nodes submit task results, if it's a PriceFeeds-type task, the Coordinator contract is responsible for verifying
the submitted signatures through threshold signature verification. If it's a VRF-type task, the Coordinator contract
needs to reconstruct the random hash from the submitted proof.
First, you need to define how to initiate a VRF oracle request in the contract.

### C. Oracle Contract
```csharp
State.OracleContract.SendRequest.Send(new SendRequestInput
{
SubscriptionId = SubscriptionId,
RequestTypeIndex = 2,
SpecificData = specificData,
TraceId = XXXXX // HASH
});
```

The official contract provided decouples Oracle nodes and Consumer contracts from business logic. It has three main
functionalities:
- `OracleContract`: This is the target contract address, the oracle contract.
- `SendRequest`: This is the method name for sending the VRF Request to the target contract.
- `SendRequestInput`: This is the input parameter of the method for sending transactions to the target contract

#### a. Subscription Feature:
| Param Name | Explanation | |
| ---------------- | ------------------------------------------------------------------ | --------------------------- |
| SubscriptionId | manage the service fee based on this subscription id | int32 |
| RequestTypeIndex | Task Type | int32, 1=Datafeeds \| 2=VRF |
| SpecificData | Detailed description of Datafeeds tasks | ByteString |
| TraceId | This ID can be used as a unique index to manage your oracle tasks. | Aelf.Hash |

Provides subscription management functionality for user contracts, enabling task initiation through subscriptions.
#### 3.3.1 How to generate VRF SpecificData

#### b. Node Management Feature:
First, you need to specify an oracle node to perform your random number generation task,

Implements the registration and role assignment of Oracle nodes, with configurable parameters for threshold signature.
```csharp
var keyHashs = State.OracleContract.GetProvingKeyHashes.Call(new Empty());
var keyHash = keyHashs[0]
```

#### c. Event-Driven Feature:
Then bind the oracle node Keyhash in your VRF task and specify the number of random numbers to be generated.

Oracle nodes need to listen to events from this contract, triggering corresponding operations when events are emitted.
```csharp
var specificData = new AetherLink.Contracts.VRF.Coordinator.SpecificData
{
KeyHash = keyHash,
NumWords = 3,
RequestConfirmations = 1
}.ToByteString()
```

The whole project structure:
#### 3.3.2 How to handle oracle pricefeeds callbacks

![structure](/img/AetherLinkStructure.png)
```csharp
public override Empty HandleOracleFulfillment(HandleOracleFulfillmentInput input)
{
var randomHashList = HashList.Parser.ParseFrom(input.Response);
State.RandomHashes[input.RequestId] = randomHashList;
}
```

0 comments on commit 63a95f1

Please sign in to comment.