mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
557 lines
25 KiB
Cap'n Proto
557 lines
25 KiB
Cap'n Proto
@0x8ffce8033734ab02;
|
|
|
|
# IDs And Hashes
|
|
##############################
|
|
|
|
struct Key256 @0xdde44e3286f6a90d {
|
|
u0 @0 :UInt64;
|
|
u1 @1 :UInt64;
|
|
u2 @2 :UInt64;
|
|
u3 @3 :UInt64;
|
|
}
|
|
|
|
struct Signature512 @0x806749043a129c12 {
|
|
u0 @0 :UInt64;
|
|
u1 @1 :UInt64;
|
|
u2 @2 :UInt64;
|
|
u3 @3 :UInt64;
|
|
u4 @4 :UInt64;
|
|
u5 @5 :UInt64;
|
|
u6 @6 :UInt64;
|
|
u7 @7 :UInt64;
|
|
}
|
|
|
|
struct Nonce24 @0xb6260db25d8d7dfc {
|
|
u0 @0 :UInt64;
|
|
u1 @1 :UInt64;
|
|
u2 @2 :UInt64;
|
|
}
|
|
|
|
using PublicKey = Key256; # Node id / Hash / DHT key / Route id, etc
|
|
using Nonce = Nonce24; # One-time encryption nonce
|
|
using Signature = Signature512; # Signature block
|
|
using TunnelID = UInt64; # Id for tunnels
|
|
using CryptoKind = UInt32; # FOURCC code for cryptography type
|
|
using ValueSeqNum = UInt32; # sequence numbers for values
|
|
using Subkey = UInt32; # subkey index for dht
|
|
|
|
struct TypedKey @0xe2d567a9f1e61b29 {
|
|
kind @0 :CryptoKind;
|
|
key @1 :PublicKey;
|
|
}
|
|
|
|
struct TypedSignature @0x963170c7298e3884 {
|
|
kind @0 :CryptoKind;
|
|
signature @1 :Signature;
|
|
}
|
|
|
|
# Node Dial Info
|
|
################################################################
|
|
|
|
struct AddressIPV4 @0xdb8769881266a6a0 {
|
|
addr @0 :UInt32; # Address in big endian format
|
|
}
|
|
|
|
struct AddressIPV6 @0xb35d6e6011dc5c20 {
|
|
addr0 @0 :UInt32; # \
|
|
addr1 @1 :UInt32; # \ Address in big
|
|
addr2 @2 :UInt32; # / endian format
|
|
addr3 @3 :UInt32; # /
|
|
}
|
|
|
|
struct Address @0x812706e9e57d108b {
|
|
union {
|
|
ipv4 @0 :AddressIPV4;
|
|
ipv6 @1 :AddressIPV6;
|
|
}
|
|
}
|
|
|
|
struct SocketAddress @0x82df4272f4dd3a62 {
|
|
address @0 :Address;
|
|
port @1 :UInt16;
|
|
}
|
|
|
|
enum ProtocolKind @0xde0bf5787c067d5a {
|
|
udp @0;
|
|
ws @1;
|
|
wss @2;
|
|
tcp @3;
|
|
}
|
|
|
|
struct DialInfoUDP @0xbb38a8b8b7024a7c {
|
|
socketAddress @0 :SocketAddress;
|
|
}
|
|
|
|
struct DialInfoTCP @0x9e0a9371b9a9f7fc {
|
|
socketAddress @0 :SocketAddress;
|
|
}
|
|
|
|
struct DialInfoWS @0xd7795f7a92ab15b0 {
|
|
socketAddress @0 :SocketAddress;
|
|
request @1 :Text;
|
|
}
|
|
|
|
struct DialInfoWSS @0xe639faa41b7d7b04 {
|
|
socketAddress @0 :SocketAddress;
|
|
request @1 :Text;
|
|
}
|
|
|
|
struct DialInfo @0xe1cd1c39fc2defdf {
|
|
union {
|
|
udp @0 :DialInfoUDP;
|
|
tcp @1 :DialInfoTCP;
|
|
ws @2 :DialInfoWS;
|
|
wss @3 :DialInfoWSS;
|
|
}
|
|
}
|
|
|
|
# Signals
|
|
##############################
|
|
|
|
struct SignalInfoHolePunch @0xeeb9ab6861890c9a {
|
|
receipt @0 :Data; # receipt to return with hole punch
|
|
peerInfo @1 :PeerInfo; # peer info of the signal sender for hole punch attempt
|
|
}
|
|
|
|
struct SignalInfoReverseConnect @0xd9ebd3bd0d46e013 {
|
|
receipt @0 :Data; # receipt to return with reverse connect
|
|
peerInfo @1 :PeerInfo; # peer info of the signal sender for reverse connect attempt
|
|
}
|
|
|
|
# Private Routes
|
|
##############################
|
|
|
|
struct RouteHopData @0x8ce231f9d1b7adf2 {
|
|
nonce @0 :Nonce; # nonce for encrypted blob
|
|
blob @1 :Data; # encrypted blob with ENC(nonce,DH(PK,SK))
|
|
# if this is a safety route RouteHopData, there is a single byte tag appended to the end of the encrypted blob
|
|
# it can be one of:
|
|
# if more hops remain in this route: RouteHop (0 byte appended as tag)
|
|
# if end of safety route and starting private route: PrivateRoute (1 byte appended as tag)
|
|
# if this is a private route RouteHopData, only can decode to RouteHop, no tag is appended
|
|
}
|
|
|
|
struct RouteHop @0xf8f672d75cce0c3b {
|
|
node :union {
|
|
nodeId @0 :PublicKey; # node id key only for established routes (kind is the same as the pr or sr it is part of)
|
|
peerInfo @1 :PeerInfo; # full peer info for this hop to establish the route
|
|
}
|
|
nextHop @2 :RouteHopData; # optional: If this the end of a private route, this field will not exist
|
|
# if this is a safety route routehop, this field is not optional and must exist
|
|
}
|
|
|
|
struct PrivateRoute @0x8a83fccb0851e776 {
|
|
publicKey @0 :TypedKey; # private route public key (unique per private route)
|
|
hopCount @1 :UInt8; # Count of hops left in the private route (for timeout calculation purposes only)
|
|
hops :union {
|
|
firstHop @2 :RouteHop; # first hop of a private route is unencrypted (hopcount > 0)
|
|
data @3 :RouteHopData; # private route has more hops (hopcount > 0 && hopcount < total_hopcount)
|
|
empty @4 :Void; # private route has ended (hopcount = 0)
|
|
}
|
|
}
|
|
|
|
struct SafetyRoute @0xf554734d07cb5d59 {
|
|
publicKey @0 :TypedKey; # safety route public key (unique per safety route)
|
|
hopCount @1 :UInt8; # Count of hops left in the safety route (for timeout calculation purposes only)
|
|
hops :union {
|
|
data @2 :RouteHopData; # safety route has more hops
|
|
private @3 :PrivateRoute; # safety route has ended and private route follows
|
|
}
|
|
}
|
|
|
|
# Operations
|
|
##############################
|
|
|
|
enum NetworkClass @0x8cebfc2a6230717f {
|
|
invalid @0; # X = Invalid network class, network is not yet set up
|
|
inboundCapable @1; # I = Inbound capable without relay, may require signal
|
|
outboundOnly @2; # O = Outbound only, inbound relay required except with reverse connect signal
|
|
webApp @3; # W = PWA, outbound relay is required in most cases
|
|
}
|
|
|
|
enum DialInfoClass @0x880005edfdd38b1e {
|
|
direct @0; # D = Directly reachable with public IP and no firewall, with statically configured port
|
|
mapped @1; # M = Directly reachable with via portmap behind any NAT or firewalled with dynamically negotiated port
|
|
fullConeNAT @2; # F = Directly reachable device without portmap behind full-cone NAT
|
|
blocked @3; # B = Inbound blocked at firewall but may hole punch with public address
|
|
addressRestrictedNAT @4; # A = Device without portmap behind address-only restricted NAT
|
|
portRestrictedNAT @5; # P = Device without portmap behind address-and-port restricted NAT
|
|
}
|
|
|
|
enum Sequencing @0xb6735890f7818a1c {
|
|
noPreference @0;
|
|
preferOrdered @1;
|
|
ensureOrdered @2;
|
|
}
|
|
|
|
struct DialInfoDetail @0x96423aa1d67b74d8 {
|
|
dialInfo @0 :DialInfo;
|
|
class @1 :DialInfoClass;
|
|
}
|
|
|
|
struct PublicInternetNodeStatus @0x9c9d7f1f12eb088f {
|
|
willRoute @0 :Bool;
|
|
willTunnel @1 :Bool;
|
|
willSignal @2 :Bool;
|
|
willRelay @3 :Bool;
|
|
willValidateDialInfo @4 :Bool;
|
|
}
|
|
|
|
struct LocalNetworkNodeStatus @0x957f5bfed2d0b5a5 {
|
|
willRelay @0 :Bool;
|
|
willValidateDialInfo @1 :Bool;
|
|
}
|
|
|
|
struct NodeStatus @0xd36b9e7a3bf3330d {
|
|
union {
|
|
publicInternet @0 :PublicInternetNodeStatus;
|
|
localNetwork @1 :LocalNetworkNodeStatus;
|
|
}
|
|
}
|
|
|
|
struct ProtocolTypeSet @0x82f12f55a1b73326 {
|
|
udp @0 :Bool;
|
|
tcp @1 :Bool;
|
|
ws @2 :Bool;
|
|
wss @3 :Bool;
|
|
}
|
|
|
|
struct AddressTypeSet @0x9f52d5430d349e6b {
|
|
ipv4 @0 :Bool;
|
|
ipv6 @1 :Bool;
|
|
}
|
|
|
|
struct SenderInfo @0x8a4464fab4b1d101 {
|
|
socketAddress @0 :SocketAddress; # socket address that for the sending peer
|
|
}
|
|
|
|
struct NodeInfo @0xe125d847e3f9f419 {
|
|
networkClass @0 :NetworkClass; # network class of this node
|
|
outboundProtocols @1 :ProtocolTypeSet; # protocols that can go outbound
|
|
addressTypes @2 :AddressTypeSet; # address types supported
|
|
envelopeSupport @3 :List(UInt8); # supported rpc envelope/receipt versions
|
|
cryptoSupport @4 :List(CryptoKind); # cryptography systems supported
|
|
dialInfoDetailList @5 :List(DialInfoDetail); # inbound dial info details for this node
|
|
}
|
|
|
|
struct SignedDirectNodeInfo @0xe0e7ea3e893a3dd7 {
|
|
nodeInfo @0 :NodeInfo; # node info
|
|
timestamp @1 :UInt64; # when signed node info was generated
|
|
signatures @2 :List(TypedSignature); # signatures
|
|
}
|
|
|
|
struct SignedRelayedNodeInfo @0xb39e8428ccd87cbb {
|
|
nodeInfo @0 :NodeInfo; # node info
|
|
relayIds @1 :List(TypedKey); # node ids for relay
|
|
relayInfo @2 :SignedDirectNodeInfo; # signed node info for relay
|
|
timestamp @3 :UInt64; # when signed node info was generated
|
|
signatures @4 :List(TypedSignature); # signatures
|
|
}
|
|
|
|
struct SignedNodeInfo @0xd2478ce5f593406a {
|
|
union {
|
|
direct @0 :SignedDirectNodeInfo; # node info for nodes reachable without a relay
|
|
relayed @1 :SignedRelayedNodeInfo; # node info for nodes requiring a relay
|
|
}
|
|
}
|
|
|
|
struct PeerInfo @0xfe2d722d5d3c4bcb {
|
|
nodeIds @0 :List(TypedKey); # node ids for 'closer peer'
|
|
signedNodeInfo @1 :SignedNodeInfo; # signed node info for 'closer peer'
|
|
}
|
|
|
|
struct RoutedOperation @0xcbcb8535b839e9dd {
|
|
sequencing @0 :Sequencing; # sequencing preference to use to pass the message along
|
|
signatures @1 :List(Signature); # signatures from nodes that have handled the private route
|
|
nonce @2 :Nonce; # nonce Xmsg
|
|
data @3 :Data; # operation encrypted with ENC(Xmsg,DH(PKapr,SKbsr))
|
|
}
|
|
|
|
struct OperationStatusQ @0x865d80cea70d884a {
|
|
nodeStatus @0 :NodeStatus; # Optional: node status update about the statusq sender
|
|
}
|
|
|
|
struct OperationStatusA @0xb306f407fa812a55 {
|
|
nodeStatus @0 :NodeStatus; # Optional: returned node status
|
|
senderInfo @1 :SenderInfo; # Optional: info about StatusQ sender from the perspective of the replier
|
|
}
|
|
|
|
struct OperationValidateDialInfo @0xbc716ad7d5d060c8 {
|
|
dialInfo @0 :DialInfo; # dial info to use for the receipt
|
|
receipt @1 :Data; # receipt to return to dial info to prove it is reachable
|
|
redirect @2 :Bool; # request a different node do the validate
|
|
}
|
|
|
|
struct OperationReturnReceipt @0xeb0fb5b5a9160eeb {
|
|
receipt @0 :Data; # receipt being returned to its origin
|
|
}
|
|
|
|
struct OperationFindNodeQ @0xfdef788fe9623bcd {
|
|
nodeId @0 :TypedKey; # node id to locate
|
|
}
|
|
|
|
struct OperationFindNodeA @0xa84cf2fb40c77089 {
|
|
peers @0 :List(PeerInfo); # returned 'closer peer' information
|
|
}
|
|
|
|
struct OperationRoute @0x96741859ce6ac7dd {
|
|
safetyRoute @0 :SafetyRoute; # where this should go
|
|
operation @1 :RoutedOperation; # the operation to be routed
|
|
}
|
|
|
|
struct OperationAppCallQ @0xade67b9f09784507 {
|
|
message @0 :Data; # opaque request to application
|
|
}
|
|
|
|
struct OperationAppCallA @0xf7c797ac85f214b8 {
|
|
message @0 :Data; # opaque response from application
|
|
}
|
|
|
|
struct OperationAppMessage @0x9baf542d81b411f5 {
|
|
message @0 :Data; # opaque message to application
|
|
}
|
|
|
|
struct SubkeyRange {
|
|
start @0 :Subkey; # the start of a subkey range
|
|
end @1 :Subkey; # the end of a subkey range
|
|
}
|
|
|
|
struct ValueData @0xb4b7416f169f2a3d {
|
|
seq @0 :ValueSeqNum; # sequence number of value
|
|
data @1 :Data; # value or subvalue contents
|
|
owner @2 :PublicKey; # the public key of the owner
|
|
writer @3 :PublicKey; # the public key of the writer
|
|
signature @4 :Signature; # signature of data at this subkey, using the writer key (which may be the same as the owner key)
|
|
# signature covers:
|
|
# * ownerKey
|
|
# * subkey
|
|
# * sequence number
|
|
# * data
|
|
# signature does not need to cover schema because schema is validated upon every set
|
|
# so the data either fits, or it doesn't.
|
|
schema @5 :Data; # (optional) the schema in use
|
|
# If not set and seqnum == 0, uses the default schema.
|
|
# If not set and If seqnum != 0, the schema must have been set prior and no other schema may be used, but this field may be eliminated to save space
|
|
# Changing this after key creation is not supported as it would change the dht key
|
|
# Schema data is signed by ownerKey and is verified both by set and get operations
|
|
}
|
|
|
|
struct OperationGetValueQ @0xf88a5b6da5eda5d0 {
|
|
key @0 :TypedKey; # the location of the value
|
|
subkey @1 :Subkey; # the index of the subkey
|
|
wantSchema @2 :Bool; # whether or not to include the schema for the key
|
|
}
|
|
|
|
|
|
struct OperationGetValueA @0xd896bb46f2e0249f {
|
|
union {
|
|
data @0 :ValueData; # the value if successful
|
|
peers @1 :List(PeerInfo); # returned 'closer peer' information if not successful
|
|
}
|
|
}
|
|
|
|
struct OperationSetValueQ @0xbac06191ff8bdbc5 {
|
|
key @0 :TypedKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
|
|
subkey @1 :Subkey; # the index of the subkey
|
|
value @2 :ValueData; # value or subvalue contents (older or equal seq number gets dropped)
|
|
}
|
|
|
|
struct OperationSetValueA @0x9378d0732dc95be2 {
|
|
union {
|
|
schemaError @0 :Void; # Either the schema is not available at the node, or the data does not match the schema that is there
|
|
data @1 :ValueData; # the new value if successful, may be a different value than what was set if the seq number was lower or equal
|
|
peers @2 :List(PeerInfo); # returned 'closer peer' information if this node is refusing to store the key
|
|
}
|
|
}
|
|
|
|
struct OperationWatchValueQ @0xf9a5a6c547b9b228 {
|
|
key @0 :TypedKey; # key for value to watch
|
|
subkeys @1 :List(SubkeyRange); # subkey range to watch, if empty, watch everything
|
|
expiration @2 :UInt64; # requested timestamp when this watch will expire in usec since epoch (can be return less, 0 for max)
|
|
count @3 :UInt32; # requested number of changes to watch for (0 = cancel, 1 = single shot, 2+ = counter, UINT32_MAX = continuous)
|
|
signature @4 :Signature; # signature of the watcher, must be one of the schema members or the key owner. signature covers: key, subkeys, expiration, count
|
|
}
|
|
|
|
struct OperationWatchValueA @0xa726cab7064ba893 {
|
|
expiration @0 :UInt64; # timestamp when this watch will expire in usec since epoch (0 if watch failed)
|
|
peers @1 :List(PeerInfo); # returned list of other nodes to ask that could propagate watches
|
|
}
|
|
|
|
struct OperationValueChanged @0xd1c59ebdd8cc1bf6 {
|
|
key @0 :TypedKey; # key for value that changed
|
|
subkeys @1 :List(SubkeyRange); # subkey range that changed (up to 512 ranges at a time)
|
|
count @2 :UInt32; # remaining changes left (0 means watch has expired)
|
|
value @3 :ValueData; # first value that changed (the rest can be gotten with getvalue)
|
|
}
|
|
|
|
struct OperationSupplyBlockQ @0xadbf4c542d749971 {
|
|
blockId @0 :TypedKey; # hash of the block we can supply
|
|
}
|
|
|
|
struct OperationSupplyBlockA @0xf003822e83b5c0d7 {
|
|
union {
|
|
expiration @0 :UInt64; # when the block supplier entry will need to be refreshed
|
|
peers @1 :List(PeerInfo); # returned 'closer peer' information if not successful
|
|
}
|
|
}
|
|
|
|
struct OperationFindBlockQ @0xaf4353ff004c7156 {
|
|
blockId @0 :TypedKey; # hash of the block to locate
|
|
}
|
|
|
|
struct OperationFindBlockA @0xc51455bc4915465d {
|
|
data @0 :Data; # Optional: the actual block data if we have that block ourselves
|
|
# null if we don't have a block to return
|
|
suppliers @1 :List(PeerInfo); # returned list of suppliers if we have them
|
|
peers @2 :List(PeerInfo); # returned 'closer peer' information
|
|
}
|
|
|
|
struct OperationSignal @0xd4f94f2a5d207e49 {
|
|
union {
|
|
holePunch @0 :SignalInfoHolePunch;
|
|
reverseConnect @1 :SignalInfoReverseConnect;
|
|
}
|
|
}
|
|
|
|
enum TunnelEndpointMode @0xef06f4c29beb7458 {
|
|
raw @0; # raw tunnel
|
|
turn @1; # turn tunnel
|
|
}
|
|
|
|
enum TunnelError @0xb82c6bfb1ec38c7c {
|
|
badId @0; # Tunnel ID was rejected
|
|
noEndpoint @1; # Endpoint was unreachable
|
|
rejectedMode @2; # Endpoint couldn't provide mode
|
|
noCapacity @3; # Endpoint is full
|
|
}
|
|
|
|
struct TunnelEndpoint @0xc2602aa983cc337d {
|
|
mode @0 :TunnelEndpointMode; # what kind of endpoint this is
|
|
description @1 :Text; # endpoint description (TODO)
|
|
}
|
|
|
|
struct FullTunnel @0x9821c3dc75373f63 {
|
|
id @0 :TunnelID; # tunnel id to use everywhere
|
|
timeout @1 :UInt64; # duration from last data when this expires if no data is sent or received
|
|
local @2 :TunnelEndpoint; # local endpoint
|
|
remote @3 :TunnelEndpoint; # remote endpoint
|
|
}
|
|
|
|
struct PartialTunnel @0x827a7ebc02be2fc8 {
|
|
id @0 :TunnelID; # tunnel id to use everywhere
|
|
timeout @1 :UInt64; # timestamp when this expires if not completed
|
|
local @2 :TunnelEndpoint; # local endpoint
|
|
}
|
|
|
|
struct OperationStartTunnelQ @0xa9c49afce44187af {
|
|
id @0 :TunnelID; # tunnel id to use everywhere
|
|
localMode @1 :TunnelEndpointMode; # what kind of local endpoint mode is being requested
|
|
depth @2 :UInt8; # the number of nodes in the tunnel
|
|
}
|
|
|
|
struct OperationStartTunnelA @0x818162e4cc61bf1e {
|
|
union {
|
|
partial @0 :PartialTunnel; # the first half of the tunnel
|
|
error @1 :TunnelError; # if we didn't start the tunnel, why not
|
|
}
|
|
}
|
|
|
|
struct OperationCompleteTunnelQ @0xe978594588eb950b {
|
|
id @0 :TunnelID; # tunnel id to use everywhere
|
|
localMode @1 :TunnelEndpointMode; # what kind of local endpoint mode is being requested
|
|
depth @2 :UInt8; # the number of nodes in the tunnel
|
|
endpoint @3 :TunnelEndpoint; # the remote endpoint to complete
|
|
}
|
|
|
|
struct OperationCompleteTunnelA @0x84090791bb765f2a {
|
|
union {
|
|
tunnel @0 :FullTunnel; # the tunnel description
|
|
error @1 :TunnelError; # if we didn't complete the tunnel, why not
|
|
}
|
|
}
|
|
|
|
struct OperationCancelTunnelQ @0xae2811ae0a003738 {
|
|
id @0 :TunnelID; # the tunnel id to cancel
|
|
}
|
|
|
|
struct OperationCancelTunnelA @0xbba23c992eff97bc {
|
|
union {
|
|
tunnel @0 :TunnelID; # the tunnel id that was cancelled
|
|
error @1 :TunnelError; # if we couldn't cancel, why not
|
|
}
|
|
}
|
|
|
|
# Things that want an answer
|
|
struct Question @0xd8510bc33492ef70 {
|
|
respondTo :union {
|
|
sender @0 :Void; # sender
|
|
privateRoute @1 :PrivateRoute; # embedded private route to be used for reply
|
|
}
|
|
detail :union {
|
|
# Direct operations
|
|
statusQ @2 :OperationStatusQ;
|
|
findNodeQ @3 :OperationFindNodeQ;
|
|
|
|
# Routable operations
|
|
appCallQ @4 :OperationAppCallQ;
|
|
getValueQ @5 :OperationGetValueQ;
|
|
setValueQ @6 :OperationSetValueQ;
|
|
watchValueQ @7 :OperationWatchValueQ;
|
|
supplyBlockQ @8 :OperationSupplyBlockQ;
|
|
findBlockQ @9 :OperationFindBlockQ;
|
|
|
|
# Tunnel operations
|
|
startTunnelQ @10 :OperationStartTunnelQ;
|
|
completeTunnelQ @11 :OperationCompleteTunnelQ;
|
|
cancelTunnelQ @12 :OperationCancelTunnelQ;
|
|
}
|
|
}
|
|
|
|
# Things that don't want an answer
|
|
struct Statement @0x990e20828f404ae1 {
|
|
detail :union {
|
|
# Direct operations
|
|
validateDialInfo @0 :OperationValidateDialInfo;
|
|
route @1 :OperationRoute;
|
|
|
|
# Routable operations
|
|
signal @2 :OperationSignal;
|
|
returnReceipt @3 :OperationReturnReceipt;
|
|
appMessage @4 :OperationAppMessage;
|
|
valueChanged @5 :OperationValueChanged;
|
|
}
|
|
}
|
|
|
|
# Things that are answers
|
|
struct Answer @0xacacb8b6988c1058 {
|
|
detail :union {
|
|
# Direct operations
|
|
statusA @0 :OperationStatusA;
|
|
findNodeA @1 :OperationFindNodeA;
|
|
|
|
# Routable operations
|
|
appCallA @2 :OperationAppCallA;
|
|
getValueA @3 :OperationGetValueA;
|
|
setValueA @4 :OperationSetValueA;
|
|
watchValueA @5 :OperationWatchValueA;
|
|
supplyBlockA @6 :OperationSupplyBlockA;
|
|
findBlockA @7 :OperationFindBlockA;
|
|
|
|
# Tunnel operations
|
|
startTunnelA @8 :OperationStartTunnelA;
|
|
completeTunnelA @9 :OperationCompleteTunnelA;
|
|
cancelTunnelA @10 :OperationCancelTunnelA;
|
|
}
|
|
}
|
|
|
|
struct Operation @0xbf2811c435403c3b {
|
|
opId @0 :UInt64; # Random RPC ID. Must be random to foil reply forgery attacks.
|
|
senderPeerInfo @1 :PeerInfo; # (optional) PeerInfo for the sender to be cached by the receiver.
|
|
targetNodeInfoTs @2 :UInt64; # Timestamp the sender believes the target's node info to be at or zero if not sent
|
|
kind :union {
|
|
question @3 :Question;
|
|
statement @4 :Statement;
|
|
answer @5 :Answer;
|
|
}
|
|
}
|