66import java .lang .invoke .MethodType ;
77
88import static org .bitcoinkernel .BitcoinKernelBindings .*;
9+ import static org .bitcoinkernel .Chainstate .*;
910
1011public 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