Skip to content

Commit 3ccb8e0

Browse files
committed
fixup: getting it to work
Signed-off-by: Simon Schrottner <[email protected]>
1 parent 571d873 commit 3ccb8e0

File tree

8 files changed

+587
-400
lines changed

8 files changed

+587
-400
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# Required Host Imports for flagd-evaluator WASM Module
2+
3+
The flagd-evaluator WASM module requires **exactly 9 host functions** to be provided. All are correctly implemented in `FlagdWasmRuntime.java`.
4+
5+
## Host Functions Overview
6+
7+
The WASM module imports these functions in the following priority:
8+
9+
### CRITICAL (2 functions) - Required for proper operation
10+
11+
1. **`get_current_time_unix_seconds`** - Provides current Unix timestamp
12+
2. **`getRandomValues`** - Provides cryptographic entropy for hash table seeding
13+
14+
### LEGACY (2 functions) - Kept for backward compatibility
15+
16+
3. **`new_0`** - Creates Date object (legacy timestamp mechanism)
17+
4. **`getTime`** - Gets timestamp from Date (legacy timestamp mechanism)
18+
19+
### ERROR HANDLING (1 function)
20+
21+
5. **`throw`** - Allows WASM to throw exceptions to host
22+
23+
### NO-OPS (4 functions) - wasm-bindgen artifacts
24+
25+
6. **`describe`** - Type description (no-op)
26+
7. **`object_drop_ref`** - Object reference counting (no-op)
27+
8. **`externref_table_grow`** - Externref table growth (no-op)
28+
9. **`externref_table_set_null`** - Externref table null setting (no-op)
29+
30+
## Complete Host Function Reference
31+
32+
| # | Module | Function | Signature | Purpose | Implementation Status |
33+
|---|--------|----------|-----------|---------|----------------------|
34+
| 1 | `host` | `get_current_time_unix_seconds` | `() -> i64` | **CRITICAL:** Provides Unix timestamp for `$flagd.timestamp` context enrichment |`createGetCurrentTimeUnixSeconds()` |
35+
| 2 | `__wbindgen_placeholder__` | `__wbg_getRandomValues_1c61fac11405ffdc` | `(i32, i32) -> nil` | **CRITICAL:** Provides cryptographic entropy for ahash (used by boon validation) |`createGetRandomValues()` |
36+
| 3 | `__wbindgen_placeholder__` | `__wbg_new_0_23cedd11d9b40c9d` | `() -> i32` | **LEGACY:** Creates Date object (may be removed in future) |`createNew0()` |
37+
| 4 | `__wbindgen_placeholder__` | `__wbg_getTime_ad1e9878a735af08` | `(i32) -> f64` | **LEGACY:** Gets timestamp from Date object |`createGetTime()` |
38+
| 5 | `__wbindgen_placeholder__` | `__wbg___wbindgen_throw_dd24417ed36fc46e` | `(i32, i32) -> nil` | Allows WASM to throw exceptions with error messages |`createWbindgenThrow()` |
39+
| 6 | `__wbindgen_placeholder__` | `__wbindgen_describe` | `(i32) -> nil` | Type description (wasm-bindgen artifact, no-op) |`createDescribe()` |
40+
| 7 | `__wbindgen_placeholder__` | `__wbindgen_object_drop_ref` | `(i32) -> nil` | Object reference counting (wasm-bindgen artifact, no-op) |`createObjectDropRef()` |
41+
| 8 | `__wbindgen_externref_xform__` | `__wbindgen_externref_table_grow` | `(i32) -> i32` | Externref table growth (wasm-bindgen artifact, no-op) |`createExternrefTableGrow()` |
42+
| 9 | `__wbindgen_externref_xform__` | `__wbindgen_externref_table_set_null` | `(i32) -> nil` | Externref table null setting (wasm-bindgen artifact, no-op) |`createExternrefTableSetNull()` |
43+
44+
## Implementation Details
45+
46+
### 1. `get_current_time_unix_seconds` - CRITICAL
47+
48+
**Purpose:** Provides the current Unix timestamp for `$flagd.timestamp` context enrichment in targeting rules.
49+
50+
**Implementation:**
51+
```java
52+
private static HostFunction createGetCurrentTimeUnixSeconds() {
53+
return new HostFunction(
54+
"host",
55+
"get_current_time_unix_seconds",
56+
FunctionType.of(
57+
List.of(),
58+
List.of(ValType.I64)
59+
),
60+
(Instance instance, long... args) -> {
61+
long currentTimeSeconds = System.currentTimeMillis() / 1000;
62+
return new long[] {currentTimeSeconds};
63+
}
64+
);
65+
}
66+
```
67+
68+
**Why this matters:**
69+
- Feature flags can use `$flagd.timestamp` in targeting rules for time-based logic
70+
- Without this function, `$flagd.timestamp` defaults to `0`, breaking time-based targeting
71+
- This is the primary mechanism for time access (the Date-based functions are legacy)
72+
73+
### 2. `getRandomValues` - CRITICAL
74+
75+
**Purpose:** Provides cryptographic entropy for `ahash` hash table seeding (used by `boon` JSON schema validation).
76+
77+
**Implementation:**
78+
```java
79+
private static HostFunction createGetRandomValues() {
80+
return new HostFunction(
81+
"__wbindgen_placeholder__",
82+
"__wbg_getRandomValues_1c61fac11405ffdc",
83+
FunctionType.of(
84+
List.of(ValType.I32, ValType.I32),
85+
List.of()
86+
),
87+
(Instance instance, long... args) -> {
88+
// CRITICAL: This is called by getrandom to get entropy for ahash
89+
// ahash uses this for hash table seed generation in boon validation
90+
int typedArrayPtr = (int) args[0]; // Unused externref handle
91+
int bufferPtr = (int) args[1]; // Pointer to buffer in WASM memory
92+
93+
// The WASM code expects a 32-byte buffer at bufferPtr
94+
// Fill it with cryptographically secure random bytes
95+
byte[] randomBytes = new byte[32];
96+
new java.security.SecureRandom().nextBytes(randomBytes);
97+
98+
Memory memory = instance.memory();
99+
memory.write(bufferPtr, randomBytes);
100+
101+
return null;
102+
}
103+
);
104+
}
105+
```
106+
107+
**Why this matters:**
108+
- The `boon` JSON schema validator uses `ahash` for hash maps
109+
- `ahash` calls `getrandom` to get entropy for hash table seeds
110+
- `getrandom` calls this host function to fill a buffer with random bytes
111+
- **Without proper random bytes, validation will fail or panic**
112+
113+
### 3-4. Date-based Timestamp Functions - LEGACY
114+
115+
**Purpose:** Legacy mechanism for getting timestamps via JavaScript Date objects.
116+
117+
**Status:** These are kept for backward compatibility but are superseded by `get_current_time_unix_seconds`. They may be removed in a future version once the WASM module is updated to only use the direct host function.
118+
119+
**Implementation:**
120+
```java
121+
// Creates a dummy Date object reference
122+
private static HostFunction createNew0() {
123+
return new HostFunction(
124+
"__wbindgen_placeholder__",
125+
"__wbg_new_0_23cedd11d9b40c9d",
126+
FunctionType.of(List.of(), List.of(ValType.I32)),
127+
(Instance instance, long... args) -> new long[] {0L}
128+
);
129+
}
130+
131+
// Returns current time in milliseconds as f64
132+
private static HostFunction createGetTime() {
133+
return new HostFunction(
134+
"__wbindgen_placeholder__",
135+
"__wbg_getTime_ad1e9878a735af08",
136+
FunctionType.of(List.of(ValType.I32), List.of(ValType.F64)),
137+
(Instance instance, long... args) -> {
138+
return new long[] {Double.doubleToRawLongBits((double) System.currentTimeMillis())};
139+
}
140+
);
141+
}
142+
```
143+
144+
### 5. `throw` - Error Handling
145+
146+
**Purpose:** Allows the WASM module to throw exceptions with error messages to the Java host.
147+
148+
**Implementation:**
149+
```java
150+
private static HostFunction createWbindgenThrow() {
151+
return new HostFunction(
152+
"__wbindgen_placeholder__",
153+
"__wbg___wbindgen_throw_dd24417ed36fc46e",
154+
FunctionType.of(List.of(ValType.I32, ValType.I32), List.of()),
155+
(Instance instance, long... args) -> {
156+
// Read error message from WASM memory
157+
int ptr = (int) args[0];
158+
int len = (int) args[1];
159+
Memory memory = instance.memory();
160+
String message = memory.readString(ptr, len);
161+
throw new RuntimeException("WASM threw: " + message);
162+
}
163+
);
164+
}
165+
```
166+
167+
### 6-9. No-op Functions - wasm-bindgen Artifacts
168+
169+
These functions are required by the wasm-bindgen glue code but don't need to do anything in our context:
170+
171+
```java
172+
// All return appropriate no-op values
173+
private static HostFunction createDescribe() { /* returns null */ }
174+
private static HostFunction createObjectDropRef() { /* returns null */ }
175+
private static HostFunction createExternrefTableGrow() { /* returns 128L */ }
176+
private static HostFunction createExternrefTableSetNull() { /* returns null */ }
177+
```
178+
179+
## Verification
180+
181+
You can verify which host functions are actually imported by the WASM module using:
182+
183+
```bash
184+
wasm-objdump -x flagd_evaluator.wasm | grep "Import\[" -A 10
185+
```
186+
187+
This will show exactly 9 imported functions matching the table above.
188+
189+
## Migration Notes
190+
191+
### Removed Functions
192+
193+
The following functions were previously documented but are **NOT** required by the current WASM module and have been removed from `FlagdWasmRuntime.java`:
194+
195+
- `__wbindgen_rethrow`
196+
- `__wbindgen_memory`
197+
- `__wbindgen_is_undefined`
198+
- `__wbindgen_string_new`
199+
- `__wbindgen_number_get`
200+
- `__wbindgen_boolean_get`
201+
- `__wbindgen_is_null`
202+
- `__wbindgen_is_object`
203+
- `__wbindgen_is_string`
204+
- `__wbindgen_object_clone_ref`
205+
- `__wbindgen_jsval_eq`
206+
- `__wbindgen_error_new`
207+
208+
These were wasm-bindgen artifacts that are not actually called by the compiled WASM module.
209+
210+
## Summary
211+
212+
✅ All 9 required host functions are correctly implemented in `FlagdWasmRuntime.java`
213+
214+
✅ The two critical functions (`get_current_time_unix_seconds` and `getRandomValues`) provide essential functionality
215+
216+
✅ The implementation has been cleaned up to include only what's actually needed
5.21 KB
Binary file not shown.

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import dev.openfeature.contrib.providers.flagd.resolver.Resolver;
44
import dev.openfeature.contrib.providers.flagd.resolver.common.FlagdProviderEvent;
5-
import dev.openfeature.contrib.providers.flagd.resolver.process.InProcessResolver;
65
import dev.openfeature.contrib.providers.flagd.resolver.process.InProcessWasmResolver;
76
import dev.openfeature.contrib.providers.flagd.resolver.rpc.RpcResolver;
87
import dev.openfeature.contrib.providers.flagd.resolver.rpc.cache.Cache;

0 commit comments

Comments
 (0)