Skip to content

Commit 04ceed9

Browse files
committed
update ContextManager class
1 parent 045c6c2 commit 04ceed9

File tree

1 file changed

+46
-187
lines changed

1 file changed

+46
-187
lines changed

src/main/java/org/bitcoinkernel/ContextManager.java

Lines changed: 46 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -6,225 +6,84 @@
66
import java.lang.invoke.MethodType;
77

88
import static org.bitcoinkernel.BitcoinKernelBindings.*;
9+
import static org.bitcoinkernel.Chainstate.*;
910

1011
public class ContextManager {
11-
// Structs for Validation Callbacks Layout
12-
private static final StructLayout VALIDATION_CALLBACK_LAYOUT = MemoryLayout.structLayout(
13-
ValueLayout.ADDRESS.withName("user_data"),
14-
ValueLayout.ADDRESS.withName("block_checked")
15-
);
16-
17-
// Structs for Notification Callbacks Layout
18-
private static final StructLayout NOTIFICATION_CALLBACK_LAYOUT = MemoryLayout.structLayout(
19-
ValueLayout.ADDRESS.withName("user_data"),
20-
ValueLayout.ADDRESS.withName("block_tip"),
21-
ValueLayout.ADDRESS.withName("header_tip"),
22-
ValueLayout.ADDRESS.withName("progress"),
23-
ValueLayout.ADDRESS.withName("warning_set"),
24-
ValueLayout.ADDRESS.withName("warning_unset"),
25-
ValueLayout.ADDRESS.withName("flush_error"),
26-
ValueLayout.ADDRESS.withName("fatal_error")
27-
);
28-
29-
// Upcall stubs for notification and validation callbacks - best way to call java code from native(C) code, read here https://docs.oracle.com/en/java/javase/24/core/upcalls-passing-java-code-function-pointer-foreign-function.html#GUID-908061BA-DC97-4524-A390-8FCEF7C5978F
30-
private static final MethodHandle BLOCK_TIP_MH;
31-
private static final MethodHandle HEADER_TIP_MH;
32-
private static final MethodHandle PROGRESS_MH;
33-
private static final MethodHandle WARNING_SET_MH;
34-
private static final MethodHandle WARNING_UNSET_MH;
35-
private static final MethodHandle FLUSH_ERROR_MH;
36-
private static final MethodHandle FATAL_ERROR_MH;
37-
private static final MethodHandle BLOCK_CHECKED_MH;
38-
39-
static {
40-
try {
41-
BLOCK_TIP_MH = MethodHandles.lookup().findVirtual(
42-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
43-
"blockTip",
44-
MethodType.methodType(void.class, int.class, MemorySegment.class, double.class)
45-
);
46-
HEADER_TIP_MH = MethodHandles.lookup().findVirtual(
47-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
48-
"headerTip",
49-
MethodType.methodType(void.class, int.class, long.class, long.class, boolean.class)
50-
);
51-
PROGRESS_MH = MethodHandles.lookup().findVirtual(
52-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
53-
"progress",
54-
MethodType.methodType(void.class, MemorySegment.class, int.class, boolean.class)
55-
);
56-
WARNING_SET_MH = MethodHandles.lookup().findVirtual(
57-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
58-
"warningSet",
59-
MethodType.methodType(void.class, int.class, MemorySegment.class)
60-
);
61-
WARNING_UNSET_MH = MethodHandles.lookup().findVirtual(
62-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
63-
"warningUnset",
64-
MethodType.methodType(void.class, int.class)
65-
);
66-
FATAL_ERROR_MH = MethodHandles.lookup().findVirtual(
67-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
68-
"fatalError",
69-
MethodType.methodType(void.class, MemorySegment.class)
70-
);
71-
FLUSH_ERROR_MH = MethodHandles.lookup().findVirtual(
72-
NotificationsManager.KernelNotificationInterfaceCallbacks.class,
73-
"flushError",
74-
MethodType.methodType(void.class, MemorySegment.class)
75-
);
76-
BLOCK_CHECKED_MH = MethodHandles.lookup().findVirtual(
77-
NotificationsManager.ValidationInterfaceCallbacks.class,
78-
"blockChecked",
79-
MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)
80-
);
81-
} catch (NoSuchMethodException | IllegalAccessException e) {
82-
throw new ExceptionInInitializerError(e);
83-
}
84-
}
8512

86-
// Context
87-
public static class Context implements AutoCloseable {
88-
private final MemorySegment inner;
89-
private final NotificationsManager.KernelNotificationInterfaceCallbacks knCallbacks;
90-
private final NotificationsManager.ValidationInterfaceCallbacks viCallbacks;
91-
private final Arena callBackArena;
92-
93-
public Context(MemorySegment inner,
94-
NotificationsManager.KernelNotificationInterfaceCallbacks knCallbacks,
95-
NotificationsManager.ValidationInterfaceCallbacks viCallbacks,
96-
Arena callBackArena) {
97-
this.inner = inner;
98-
this.knCallbacks = knCallbacks;
99-
this.viCallbacks = viCallbacks;
100-
this.callBackArena = callBackArena;
13+
// ===== Context Options =====
14+
public static class ContextOptions implements AutoCloseable {
15+
private MemorySegment inner;
16+
17+
public ContextOptions() throws KernelTypes.KernelException {
18+
this.inner = btck_context_options_create.makeInvoker().apply();
19+
if (inner == MemorySegment.NULL) {
20+
throw new KernelTypes.KernelException("Failed to instantiate ContextOptions object");
21+
}
10122
}
10223

103-
public boolean interrupt() {
104-
return kernel_context_interrupt(inner);
24+
public void setChainParams(ChainParameters chainParams) {
25+
checkClosed();
26+
btck_context_options_set_chainparams(inner, chainParams.getInner());
10527
}
10628

10729
MemorySegment getInner() {
10830
return inner;
10931
}
11032

33+
private void checkClosed() {
34+
if (inner == MemorySegment.NULL) {
35+
throw new IllegalStateException("ContextOptions object has been closed already");
36+
}
37+
}
38+
11139
@Override
112-
public void close() {
113-
kernel_context_destroy(inner);
114-
callBackArena.close();
40+
public void close() throws Exception {
41+
if (inner != MemorySegment.NULL) {
42+
btck_context_options_destroy(inner);
43+
inner = MemorySegment.NULL;
44+
}
11545
}
11646
}
11747

118-
// Context Builder
119-
public static class ContextBuilder implements AutoCloseable {
48+
// ===== Context =====
49+
public static class Context implements AutoCloseable {
12050
private MemorySegment inner;
121-
private NotificationsManager.KernelNotificationInterfaceCallbacks knCallbacks;
122-
private NotificationsManager.ValidationInterfaceCallbacks viCallbacks;
123-
private final Arena callbackArena;
124-
private boolean built = false;
125-
126-
public ContextBuilder() throws KernelTypes.KernelException {
127-
this.callbackArena = Arena.ofConfined();
128-
try (var arena = Arena.ofConfined()) {
129-
this.inner = kernel_context_options_create.makeInvoker().apply();
130-
if (inner == MemorySegment.NULL) {
131-
throw new KernelTypes.KernelException("Failed to create context options");
132-
}
51+
52+
public Context() throws KernelTypes.KernelException {
53+
this.inner = btck_context_create(MemorySegment.NULL);
54+
if (inner == MemorySegment.NULL) {
55+
throw new KernelTypes.KernelException("Failed to instantiate Context object");
13356
}
13457
}
13558

136-
public ContextBuilder chainType(KernelTypes.ChainType chainType) {
137-
try (var params = new ChainParams(chainType)) {
138-
kernel_context_options_set_chainparams(inner, params.getInner());
139-
} catch (KernelTypes.KernelException e) {
140-
throw new RuntimeException(e);
59+
public Context(ContextOptions options) throws KernelTypes.KernelException {
60+
this.inner = btck_context_create(options.getInner());
61+
if (inner == MemorySegment.NULL) {
62+
throw new KernelTypes.KernelException("Failed to instantiate Context object");
14163
}
142-
return this;
14364
}
14465

145-
public ContextBuilder notificationCallbacks(NotificationsManager.KernelNotificationInterfaceCallbacks callBacks) {
146-
this.knCallbacks = callBacks;
147-
MemorySegment holder = callbackArena.allocate(NOTIFICATION_CALLBACK_LAYOUT);
148-
holder.set(ValueLayout.ADDRESS, 0, MemorySegment.ofAddress(System.identityHashCode(callBacks)));
149-
MemorySegment blockTipStub = Linker.nativeLinker().upcallStub(
150-
BLOCK_TIP_MH.bindTo(callBacks),
151-
FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_DOUBLE),
152-
callbackArena
153-
);
154-
MemorySegment headerTipStub = Linker.nativeLinker().upcallStub(
155-
HEADER_TIP_MH.bindTo(callBacks),
156-
FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_BOOLEAN),
157-
callbackArena
158-
);
159-
MemorySegment progressStub = Linker.nativeLinker().upcallStub(
160-
PROGRESS_MH.bindTo(callBacks),
161-
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.JAVA_BOOLEAN),
162-
callbackArena
163-
);
164-
MemorySegment warningSetStub = Linker.nativeLinker().upcallStub(
165-
WARNING_SET_MH.bindTo(callBacks),
166-
FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT, ValueLayout.ADDRESS),
167-
callbackArena
168-
);
169-
MemorySegment warningUnsetStub = Linker.nativeLinker().upcallStub(
170-
WARNING_UNSET_MH.bindTo(callBacks),
171-
FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT),
172-
callbackArena
173-
);
174-
MemorySegment flushErrorStub = Linker.nativeLinker().upcallStub(
175-
FLUSH_ERROR_MH.bindTo(callBacks),
176-
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
177-
callbackArena
178-
);
179-
MemorySegment fatalErrorStub = Linker.nativeLinker().upcallStub(
180-
FATAL_ERROR_MH.bindTo(callBacks),
181-
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
182-
callbackArena
183-
);
184-
holder.set(ValueLayout.ADDRESS, ValueLayout.ADDRESS.byteSize(), blockTipStub);
185-
holder.set(ValueLayout.ADDRESS, 2 * ValueLayout.ADDRESS.byteSize(), headerTipStub);
186-
holder.set(ValueLayout.ADDRESS, 3 * ValueLayout.ADDRESS.byteSize(), progressStub);
187-
holder.set(ValueLayout.ADDRESS, 4 * ValueLayout.ADDRESS.byteSize(), warningSetStub);
188-
holder.set(ValueLayout.ADDRESS, 5 * ValueLayout.ADDRESS.byteSize(), warningUnsetStub);
189-
holder.set(ValueLayout.ADDRESS, 6 * ValueLayout.ADDRESS.byteSize(), flushErrorStub);
190-
holder.set(ValueLayout.ADDRESS, 7 * ValueLayout.ADDRESS.byteSize(), fatalErrorStub);
191-
kernel_context_options_set_notifications(inner, holder);
192-
return this;
66+
public boolean interrupt() {
67+
checkClosed();
68+
return btck_context_interrupt(inner) == 0;
19369
}
19470

195-
public ContextBuilder validationiInterface(NotificationsManager.ValidationInterfaceCallbacks callbacks) throws KernelTypes.KernelException{
196-
this.viCallbacks = callbacks;
197-
MemorySegment holder = callbackArena.allocate(VALIDATION_CALLBACK_LAYOUT);
198-
holder.set(ValueLayout.ADDRESS, 0, MemorySegment.ofAddress(System.identityHashCode(callbacks)));
199-
200-
MemorySegment blockCheckStub = Linker.nativeLinker().upcallStub(
201-
BLOCK_CHECKED_MH.bindTo(callbacks),
202-
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS),
203-
callbackArena
204-
);
205-
holder.set(ValueLayout.ADDRESS, ValueLayout.ADDRESS.byteSize(), blockCheckStub);
206-
kernel_context_options_set_validation_interface(inner, holder);
207-
return this;
71+
MemorySegment getInner() {
72+
return inner;
20873
}
20974

210-
public Context build() throws KernelTypes.KernelException {
211-
MemorySegment contextInner = kernel_context_create(inner);
212-
if (contextInner == MemorySegment.NULL) {
213-
throw new KernelTypes.KernelException("Failed to create context");
75+
private void checkClosed() {
76+
if (inner == MemorySegment.NULL) {
77+
throw new IllegalStateException("Context object is already closed");
21478
}
215-
kernel_context_options_destroy(inner);
216-
inner = MemorySegment.NULL;
217-
built = true;
218-
return new Context(contextInner, knCallbacks, viCallbacks, callbackArena);
21979
}
22080

22181
@Override
222-
public void close() {
223-
if (!built && inner != MemorySegment.NULL) {
224-
kernel_context_options_destroy(inner);
82+
public void close() throws Exception {
83+
if (inner != MemorySegment.NULL) {
84+
btck_context_destroy(inner);
22585
inner = MemorySegment.NULL;
22686
}
227-
// callbackArena.close();
22887
}
22988
}
23089
}

0 commit comments

Comments
 (0)