-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move node configuration to runtime #917
Conversation
Note that I have not fixed the glue code, and therefore some tests are currently failing. My intention is to submit this only after we switch to using the Rust |
(but please do review in its current state, and let me know if you have any suggestions on whether I should go ahead and fix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just on a quick look at the config proto change, my immediate concern is still that this approach removes an important layer of protection from the system.
It looks like this change will mean that an Oak application can create a (say) GrpcClientConfiguration
at runtime and then just connect to any gRPC server anywhere, whereas previously there were obvious and easily-checkable constraints imposed by the configuration: if the config didn't include a gRPC/Storage/Roughtime node, then you could be very sure that the running Node didn't do gRPC/Storage/Roughtime.
Of course, this sort of access to the outside world should eventually be policed by the IFC/label system, but (particularly) until that's fully in place I like the belt-and-braces approach of having defense-in-depth: an outer perimeter that places gross restrictions on what an app can do (gRPC:✗ Storage: ✓ Roughtime: ✗), combined with an inner IFC system (do the label flows allow this particular node/channel operation?).
(If I squint hard and talk fast, I can almost spin this in capability terms: in the current system, an app is born with the capabilities to create particular types of pseudo-Nodes, whereas a fully dynamic system is effectively making a global namespace available to the app.)
(Also, apologies if I'm getting the wrong end of the stick, I only took a quick look.)
docs/abi.md
Outdated
handle to the read half of a channel identified by arg 4. | ||
|
||
The Node configuration is a serialized | ||
[`NodeConfiguration`](/oak/proto/application.proto) probobuf message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/probobuf/protobuf/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
oak/proto/application.proto
Outdated
// | ||
// See https://webassembly.org/docs/binary-encoding/ . | ||
// | ||
// Entries in this map may be references by instances of WebAssemblyConfiguration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/references/referenced/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// | ||
// Entries in this map may be references by instances of WebAssemblyConfiguration | ||
// objects. | ||
map<string, bytes> wasm_modules = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking: are all of our platforms happy with map
types in protos?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes maps are just syntactic sugar for a repeated message generated by the proto compiler, they have to dedicated wire representation.
https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility
// The name of an exported Web Assembly function in the initial Node to | ||
// be used as the Node's main entrypoint. | ||
string initial_entrypoint_name = 3; | ||
// Map from Wasm module names to their bytecode representation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be nice to make it clear that the only third-party code that gets run as part of an Oak application has to be present as an entry in this map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Thanks @daviddrysdale , yes I agree that this is indeed removing one layer of protection, but I think this is a layer that is not Oak's goal, and even if it is there, cannot really be leveraged in a meaningful way in its current form. At least, I don't see a path forward in which this extra forced declaration (having the application declare upfront the kind of nodes it uses locally) could be made useful to clients. There is no mechanism for clients to inspect the configuration of a running application; even if there were, the application configuration is in a way an imprecise upper bound on the kind of capabilities that the application may rely on, and on the other hand it is not even good at that, because it does not enforce transitivity (e.g. if the application has a single egress gRPC client node, it may be tempting to conclude that it does not have storage, but the other side of the gRPC connection may actually be an application that has storage, etc.) this is the reason why we chose DIFC, which allows to reason about constraints in a distributed system. Even if we wanted to limit the functionality of an application to have some reassurance against local untrusted code, I think the current mechanism couples configuration and constraints too much; if we wanted to disable gRPC connectivity entirely, I think an explicit top-level bool in the application configuration may be a more intentional way of expressing that. The problem again is that it would still not really propagate across applications, or to storage, or anything else. This is similar to the discussion on read / write rights on handles vs relying on information flow: the point of Oak is not to be a pure capability-based OS, it is to enforce policies in distributed systems, and sometimes being a pure capability system is at odd with that, or at the very least it does not add value (except perhaps some very localized value that does not extend to the rest of the system). But it's also certainly not impossible that some theory can unify both approaches at some point. In the end, the way I see these things resolved is that effectively, client labels are capabilities of the kind of nodes that may manipulate the data; for instance, in order to allow storage, data would need to be labelled with a hypothetical storage pseudo-node secrecy label, which would allow such data to flow there (and not to other nodes); it is as if the data comes along with the capability to unlock that particular node type. It is a bit more nuanced than that, but perhaps this captures your intuition of some of this being in the spirit of capability-oriented systems. WDYT? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defence-in-depth concerns aside, the code changes do fall out quite nicely…
config_type: Some(ConfigType::GrpcClientConfig(GrpcClientConfiguration { | ||
address: "127.0.0.1:8888".to_string(), | ||
})), | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having helpers in the SDK for configuring standard pseudo-Node types would be helpful across all of the examples, e.g. so this could look something like:
match oak::grpc::client::Client::new(&oak::node_config::grpc_client("127.0.0.1:888"))
.map(AggregatorClient)
{
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea, done.
examples/hello_world/config/BUILD
Outdated
@@ -45,5 +45,5 @@ serialized_config( | |||
"app": "//:target/wasm32-unknown-unknown/release/hello_world.wasm", | |||
"translator": "//:target/wasm32-unknown-unknown/release/translator.wasm", | |||
}, | |||
textproto = ":config_translator.textproto", | |||
textproto = ":config.textproto", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the change here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted the other config, since now they are identical. I can keep both if you prefer though, let me know.
@@ -1,19 +0,0 @@ | |||
node_configs { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this removed? It seems to remove the ability to run hello_world
with a translator
module configured.
Some(ConfigType::WasmConfig(WebAssemblyConfiguration { module_bytes, .. })) => { | ||
load_wasm(&module_bytes).map_err(|e| { | ||
error!("Error loading Wasm module: {}", e); | ||
OakStatus::ErrInvalidArgs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like not having the data structures that mirror the protobuf config structure (and I think this would fix #755 along the way); are the validity checks (check_port
, load_wasm
) now done at a later point?
[Edit: yes they are]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Affirmative.
initial_reader, | ||
))), | ||
Some(ConfigType::RoughtimeClientConfig(_config)) => Ok(Box::new( | ||
external::PseudoNode::new(name, runtime, initial_reader), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this will need to pass a copy of the node config over the Rust->C++ FFI boundary. As you say, probably easiest to block this until main()
flips into Rust and oak_glue
gets reworked.
@@ -140,65 +147,41 @@ impl WasmInterface { | |||
(interface, handle) | |||
} | |||
|
|||
/// Corresponds to the host ABI function [`node_create: (usize, usize, usize, usize, | |||
/// u64) -> u32`](oak_abi::node_create). | |||
/// Corresponds to the host ABI function [`node_create: (usize, usize, usize, usize, u64) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment now out of date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pub fn node_create( | ||
config_buf: *const u8, | ||
config_len: usize, | ||
entrypoint_buf: *const u8, | ||
entrypoint_len: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need to update sdk/rust/oak/src/stubs.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
b826bf9
to
ff8a731
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @daviddrysdale
docs/abi.md
Outdated
handle to the read half of a channel identified by arg 4. | ||
|
||
The Node configuration is a serialized | ||
[`NodeConfiguration`](/oak/proto/application.proto) probobuf message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
config_type: Some(ConfigType::GrpcClientConfig(GrpcClientConfiguration { | ||
address: "127.0.0.1:8888".to_string(), | ||
})), | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea, done.
examples/hello_world/config/BUILD
Outdated
@@ -45,5 +45,5 @@ serialized_config( | |||
"app": "//:target/wasm32-unknown-unknown/release/hello_world.wasm", | |||
"translator": "//:target/wasm32-unknown-unknown/release/translator.wasm", | |||
}, | |||
textproto = ":config_translator.textproto", | |||
textproto = ":config.textproto", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted the other config, since now they are identical. I can keep both if you prefer though, let me know.
// The name of an exported Web Assembly function in the initial Node to | ||
// be used as the Node's main entrypoint. | ||
string initial_entrypoint_name = 3; | ||
// Map from Wasm module names to their bytecode representation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
oak/proto/application.proto
Outdated
// | ||
// See https://webassembly.org/docs/binary-encoding/ . | ||
// | ||
// Entries in this map may be references by instances of WebAssemblyConfiguration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// | ||
// Entries in this map may be references by instances of WebAssemblyConfiguration | ||
// objects. | ||
map<string, bytes> wasm_modules = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes maps are just syntactic sugar for a repeated message generated by the proto compiler, they have to dedicated wire representation.
https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility
pub fn node_create( | ||
config_buf: *const u8, | ||
config_len: usize, | ||
entrypoint_buf: *const u8, | ||
entrypoint_len: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Some(ConfigType::WasmConfig(WebAssemblyConfiguration { module_bytes, .. })) => { | ||
load_wasm(&module_bytes).map_err(|e| { | ||
error!("Error loading Wasm module: {}", e); | ||
OakStatus::ErrInvalidArgs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Affirmative.
@@ -140,65 +147,41 @@ impl WasmInterface { | |||
(interface, handle) | |||
} | |||
|
|||
/// Corresponds to the host ABI function [`node_create: (usize, usize, usize, usize, | |||
/// u64) -> u32`](oak_abi::node_create). | |||
/// Corresponds to the host ABI function [`node_create: (usize, usize, usize, usize, u64) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
} | ||
} | ||
node_configs { | ||
name: "grpc-client" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these configs deleted because they are not yet supported by Rust Runtime or they are no longer needed for abitest
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are now in the code of abitest
module itself!
@@ -92,7 +92,9 @@ impl AggregatorNode { | |||
bucket, svec | |||
); | |||
|
|||
match oak::grpc::client::Client::new("grpc-client", "").map(AggregatorClient) { | |||
match oak::grpc::client::Client::new(&oak::node_config::grpc_client("127.0.0.1:8888")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are passing an address as a function argument, does it mean that we also need to have TLS keys baked into the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we will have root CAs pinned in the oak_loader
binary, yes. I am not sure how this works currently though.
oak/common/app_config.cc
Outdated
|
||
} // namespace | ||
|
||
std::unique_ptr<ApplicationConfiguration> DefaultConfig(const std::string& module_bytes) { | ||
auto config = absl::make_unique<ApplicationConfiguration>(); | ||
config->set_grpc_port(kDefaultGrpcPort); | ||
(*config->mutable_wasm_modules())[kAppWasmModuleName] = module_bytes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does kAppWasmModuleName
always exist in this map?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, my understanding is that this will create the entry if it's not there (it seems to work so I guess that's fine?)
Let me know if I'm doing it wrong though
} | ||
(*config->mutable_wasm_modules())[module_name] = std::move(module_bytes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can [module_name]
return nullptr
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully it should be obvious if it does, anyways the size of module_info
was checked above already. Or are you suggesting something else?
) -> Self { | ||
Self { | ||
config_name: config_name.to_string(), | ||
) -> Result<Self, ConfigurationError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is new
supposed to return Result
instead of just Self
.
Should this function be called create
instead? WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am also not quite sure about naming, but I think given the return type is obvious, it should be fine either way.
/// Struct that represents a gRPC server pseudo-Node. | ||
/// | ||
/// For each gRPC request from a client, gRPC server pseudo-Node creates a pair of temporary | ||
/// channels (to write a request to and to read a response from) and passes corresponding handles to | ||
/// the [`GrpcServerNode::channel_writer`]. | ||
#[derive(Clone)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need Clone
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a question for you I guess :) I just removed the manual implementation and replaced it with derive
.
|
||
pub struct LogNode { | ||
config_name: String, | ||
name: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this field be called display_name
(just like in GrpcServerNode
and WasmNode
) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
ff8a731
to
9981b0f
Compare
cf344dc
to
a5fc54e
Compare
ce3cbad
to
974c3ba
Compare
827157c
to
9fd3153
Compare
@ipetr0v @daviddrysdale this is now ready for review. Note that I removed parts of the logic around the old ApplicationConfiguration |
examples/abitest/tests/Cargo.toml
Outdated
@@ -15,6 +15,9 @@ log = "*" | |||
oak = "=0.1.0" | |||
oak_abi = "=0.1.0" | |||
prost = "*" | |||
# Using an old version that is supported by `cargo-raze`: | |||
# https://github.com/google/cargo-raze/issues/41#issuecomment-592274128 | |||
tonic = { version = "=0.1.1", features = ["tls"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think after #1016 we can use the latest version of tonic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
1926457
to
faf5dac
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code changes LGTM and the resulting API is definitely neater and more flexible.
However, I still have the fundamental concern that this extra flexibility removes an outer security bound on the system as a whole, leaving the IFC system (which isn't implemented yet) as the only intrinsic security boundary. Maybe re-awaken the earlier discussion on Slack (which seemed to wind down without really reaching a conclusion/consensus)?
docs/programming-oak.md
Outdated
``` | ||
<!-- prettier-ignore-end --> | ||
|
||
The `module_bytes: "<bytes>"` means that this value will be filled with | ||
WebAssembly module bytes after serialization using the | ||
The `wasm_modules` field (not shown above because empty in the template |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"because it is empty"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. (I thought my version was grammatically correct though, was it not?)
grpc_client_root_tls_certificate: Some(Certificate::from_pem("invalid-cert")), | ||
}, | ||
) | ||
.expect("unable to configure runtime with test wasm"); | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are other docs that need updating for this API change:
- concepts.md section "Oak Application": still talks about "allowed contents of the Nodes"
- "Running an Oak Application" section earlier in this doc: still talks about the config including the gRPC port.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both done.
oak/proto/application.proto
Outdated
@@ -22,27 +22,33 @@ package oak.application; | |||
// | |||
// An Oak Application is built from a collection of interconnected Nodes, | |||
// each of which is running the code described by an entry in this | |||
// configuration. These Nodes are created dynamically at runtime, with | |||
// configuration. These Nodes are created dynamically at runtime, with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first sentence of this comment is no longer accurate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworded.
sdk/rust/oak_tests/Cargo.toml
Outdated
lazy_static = "*" | ||
log = { version = "*", features = ["std"] } | ||
oak = "=0.1.0" | ||
oak_abi = "=0.1.0" | ||
oak_runtime = { version = "=0.1.0", features = ["test_build"] } | ||
prost = "*" | ||
rand = { version = "*" } | ||
cargo_metadata = "*" | ||
# Using an old version that is supported by `cargo-raze`: | ||
# https://github.com/google/cargo-raze/issues/41#issuecomment-592274128 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Up-rev here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// Some of the tests require a gRPC client, so we populate the required certificate with | ||
// an invalid value here, even though it will still fail when instantiating the actual | ||
// gRPC client. | ||
grpc_client_root_tls_certificate: Some(Certificate::from_pem("invalid-cert")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't None
work here, btw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it would cause it to fail too early, for some of the tests (they would not be able to create the gRPC client at all otherwise).
@@ -32,8 +29,8 @@ mod storage; | |||
mod wasm; | |||
|
|||
/// Trait encapsulating execution of a Node or pseudo-Node. | |||
pub trait Node { | |||
/// Execute the Node, using the provided `Runtime` reference and initial handle. The method | |||
pub trait Node: Send { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouf of interest, why does this now need Send
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was already needed, but it was specified as an additional type bound on the actual node_create
function (which was quite confusing), I just moved it here instead.
@@ -108,112 +69,65 @@ impl std::fmt::Display for ConfigurationError { | |||
write!(f, "Failed to parse an address: {}", e) | |||
} | |||
ConfigurationError::IncorrectPort => write!(f, "Incorrect port (must be > 1023)"), | |||
ConfigurationError::IncorrectURI => write!(f, "Incorrect URI"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: incorrect how?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is only logged at the point where the parsing happens. I start thinking that we should probably just either log or propagate all errors, there is not much value in this halfway split. Created #1027 to track.
faf5dac
to
b7cba0d
Compare
7d4ab4a
to
ee7f1f3
Compare
The ApplicationConfiguration object is now more of a directory of executable wasm modules, and an initial Node configuration. Subsequent Nodes are created at runtime by passing the serialized NodeConfiguration protobuf message to `node_create` directly. This allows removing an extra indirection from application to the config of individual nodes, in favour of inlining configs in the Wasm code of the main node itself. Also remove parts of the logic around the old ApplicationConfiguration format from the C++ Oak Runtime, under the assumption that it is going to be deleted soon. Ref project-oak#688
ee7f1f3
to
045dc31
Compare
Reproducibility index:
|
The ApplicationConfiguration object is now more of a directory of
executable wasm modules, and an initial Node configuration.
Subsequent Nodes are created at runtime by passing the serialized
NodeConfiguration protobuf message to
node_create
directly.This allows removing an extra indirection from application to the config
of individual nodes, in favour of inlining configs in the Wasm code of
the main node itself.
Also remove parts of the logic around the old ApplicationConfiguration
format from the C++ Oak Runtime, under the assumption that it is going
to be deleted soon.
Ref #688
Checklist