Nodes announce
Each node signs the structs its organization owns and announces them to its peers with its membership token, again whenever it declares one.
Build / Structs
A struct names the shape of an object: its fields and the type of each. An organization declares it once, and anyone on the network can use it as a type in contracts, event types and resource functions, so values are checked wherever they travel instead of passing as an unchecked object.
POST /v1/structsdefineStruct01
Without structs, a contract that takes a customer takes an object, and every caller has to guess its fields. A struct gives that shape a name and a version that every node agrees on:
02
A struct is a script of its own. It declares its fields and has no body. Fields are name: type pairs of any RequestScript type, including other structs and lists of them. Unlike contracts and event types, a struct must name its version.
struct com.example.Address@1(street: string, city: string, postcode: string)
struct com.example.Customer@2(
name: string,
addresses: []com.example.Address@1,
credit: decimal
)Declare it on a node of your organization with its API key, or a run token from one of its own API clients. The node's organization owns the struct.
curl -X POST https://node.example/v1/structs \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_KEY" \
-d '{"source": "struct com.example.Address@1(street: string, city: string, postcode: string)"}'DELETE. Contracts and event types on other nodes may name any version, so a version stays declared for good.GET /v1/structs lists the structs a node knows, its own and those it learned from peers. GET /v1/structs/com.example.Address@1 returns one, or the latest version when none is named.
03
A struct type is the struct's qualified name and its version. It can appear wherever a type can: contract parameters and return types, var annotations including state variables, event type fields, and resource function types declared in TypeScript.
contract com.example.Ship(customer: com.example.Customer@2): com.example.Address@1 {
var first: com.example.Address@1 = customer.addresses[0]
return first
}
event com.example.OrderShipped(to: com.example.Address@1)A struct value is written as an object literal, and checked when it's assigned, passed or returned:
var home: com.example.Address@1 = { street: "1 Main St", city: "Springfield", postcode: "12345" }A reference without a version, like com.example.Address, is an error. A reference never moves to a later version: declaring @2 changes nothing that names @1, so every node checks a value against the same fields, whichever versions it has learned since.
04
Checking is structural and lenient, so structs from different organizations fit together:
| Case | What happens |
|---|---|
| Same fields, other struct | fits: a value fits a struct if its fields fit, whatever it was built as, including a plain object |
| Declared field | converted to its type, as an assignment would be; one that doesn't fit is a runtime error naming the struct and the field |
| Missing field | null, which fills any type, so a struct can't require a field |
| Undeclared field | kept unchanged |
object | usable where a struct is expected, checked when it's converted, and the other way around |
null | fits every struct type |
Values travel as JSON objects. An int64 or decimal that can't round-trip through a JSON number is a string. Contract state stores a struct value as the object it is.
05
A resource function can name structs in its parameter and return types. Define them with defineStruct, which takes the version as its second argument, and register them with the node, or pass them to start as structs: [Forecast].
import { defineStruct, StellariumNode } from 'stellarium-ts';
const Forecast = defineStruct('com.example.Forecast', 1, {
city: 'string',
highs: '[]decimal',
summary: 'string',
});
// In a resource function:
// returnType: Forecast.type, // 'com.example.Forecast@1'
const node = new StellariumNode();
await node.registerStruct(Forecast);
await node.register(weather);.type or as 'com.example.Address@1'.06
Structs are learned from peers, and every announcement is signed and checked against the operator, so no node can claim another organization's types.
Each node signs the structs its organization owns and announces them to its peers with its membership token, again whenever it declares one.
A starting node fetches every peer's struct announcement before it learns their event types and resources, which may refer to them.
A receiver learns a struct only if the token says the announcing node belongs to its owner. A path another organization owns, or a version with different fields, is rejected.
A struct a node learned stays known after the peer stops announcing it, since a version never goes away.
A node knows only the structs of its peers' organizations. A struct that refers to another organization's struct can't be used until the node learns that one from a node of its owner.
07
Unknown struct error before any payment or network call, and the resource's other functions still work.A struct has at most 64 fields, nests at most 8 deep counting lists of structs, and its source is at most 16 KiB.
08
Read the full reference in the stellarium-ts structs guide and the documentation. Structs need RequestScript 1.7.0, which adds struct declarations and struct types; learn the language at requestscript.org.
Published a struct others can build on? Share it on Discord.