Tellor Layer is a stand alone L1 built using the cosmos sdk for the purpose of coming to consensus on any subjective data. It works by using a network of staked parties who are crypto-economically incentivized to honestly report requested data.
For more in-depth information, checkout the Tellor Layer tech paper and our ADRs.
For docs on how to join our public testnet go here: https://docs.tellor.io/layer-docs
- Select the start script that works for you
start_one_node.sh
is for those who want to run a chain with a single validator in a mac environmentstart_one_node_aws.sh
is for those who want a chain with a single validator and the option to import a faucet account from a seed phrase to be used in a linux environmentstart_two_chains.sh
(mac environment) sets up two nodes/validators and starts one of them from this script. Then to start the other validator you would run thestart_bill.sh
script
- Run the selected script from the base layer folder:
./start_scripts/{selected_script}
To find more information please go to the layer_scripts folder.
Here you will find a detailed breakdown for how to join a chain as a node and how to create a new validator for the chain
Run the chain locally in a docker container, powered by local-ic
Install heighliner:
make get-heighliner
Create image:
make local-image
Install local interchain:
make get-localic
Start the local-devnet:
make local-devnet
To configure the chain (ie add more validators plus more) edit the json in local_devnet/chains/layer.json
To run all unit and integration tests:
make test
In addition to the unit and integration tests, there are also end to end tests using the interchaintest framework. These tests spin up a live chain with a given number of nodes/validators in docker that you can run transactions and queries against. To run all e2e tests:
Install heighliner:
make get-heighliner
Create image:
make local-image
Run all e2e tests:
make e2e
Run an individual test:
cd e2e
go test -v -run TestLayerFlow -timeout 10m
Run benchmark tests:
make bench-report
To lint per folder:
make lint-folder-fix FOLDER="x/mint"
To lint all files:
make lint
Read about queries from the Cosmos SDK team here. All nodes do not have to have the same queries. Feel free to make an issue or PR regarding any desired queries to this repo. To add a new query to layer, replace the logic as needed for GetCurrentAggregateReport
:
- In
layer/proto/layer/oracle/query.go
, define the rpc endpoint in theservice Query {}
struct.
service Query {
...
// Queries the current aggregate report by query id
rpc GetCurrentAggregateReport(QueryGetCurrentAggregateReportRequest) returns (QueryGetCurrentAggregateReportResponse) {
option (google.api.http).get = "/tellor-io/layer/oracle/get_current_aggregate_report/{query_id}";
}
...
}
- Also in
layer/proto/layer/oracle/query.go
, define a Message for the query request and query response.
// QueryGetCurrentAggregateReportRequest is the request type for the Query/GetCurrentAggregateReport RPC method.
message QueryGetCurrentAggregateReportRequest {
// query_id defines the query id hex string.
string query_id = 1;
}
// QueryGetCurrentAggregateReportResponse is the response type for the Query/GetCurrentAggregateReport RPC method.
message QueryGetCurrentAggregateReportResponse {
// aggregate defines the current aggregate report.
Aggregate aggregate = 1;
// timestamp defines the timestamp of the aggregate report.
uint64 timestamp = 2;
}
Note: When inputting or returning a list of items, use the repeated
keyword, and optional pagination. Ex. with a different query here
Note: If inputting or returning a custom type, such as Aggregate
, it needs to be defined and imported within the proto files. Ex here
-
Generate the protobuf files for the new query using a custom protoc implementation or
ignite generate proto-go
. (Ignite docs here.) -
Create the query function in layer/x/oracle/keeper/query.go or individual query file.
// gets the current aggregate report for a query id
func (k Querier) GetCurrentAggregateReport(ctx context.Context, req *types.QueryGetCurrentAggregateReportRequest) (*types.QueryGetCurrentAggregateReportResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
queryId, err := hex.DecodeString(req.QueryId)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid query id")
}
aggregate, timestamp, err := k.keeper.GetCurrentAggregateReport(ctx, queryId)
if err != nil {
return nil, err
}
timeUnix := timestamp.UnixMilli()
return &types.QueryGetCurrentAggregateReportResponse{
Aggregate: aggregate,
Timestamp: uint64(timeUnix),
}, nil
}
-
Add test(s)
-
In
layer/x/oracle/autocli.go
, add your query to theAutoCLIOptions
return
func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
return &autocliv1.ModuleOptions{
Query: &autocliv1.ServiceCommandDescriptor{
Service: modulev1.Query_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
...
{
RpcMethod: "GetCurrentAggregateReport",
Use: "get-current-aggregate-report [query_id]",
Short: "Query current aggregate report",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "query_id"}},
},
...
}
}
}
...
}
- Run
./scripts/protoc-swagger-gen.sh
to generate the swagger page documentation
This repository is maintained by the Tellor team
Check out our issues log here on Github or feel free to reach out anytime info@tellor.io
Tellor Inc. 2024