diff --git a/internal/api/bindings.h b/internal/api/bindings.h
index 5b38b7736..a2e9950a9 100644
--- a/internal/api/bindings.h
+++ b/internal/api/bindings.h
@@ -260,6 +260,16 @@ typedef struct Iterator_vtable {
struct UnmanagedVector*,
struct UnmanagedVector*,
struct UnmanagedVector*);
+ int32_t (*next_key_db)(struct iterator_t,
+ struct gas_meter_t*,
+ uint64_t*,
+ struct UnmanagedVector*,
+ struct UnmanagedVector*);
+ int32_t (*next_value_db)(struct iterator_t,
+ struct gas_meter_t*,
+ uint64_t*,
+ struct UnmanagedVector*,
+ struct UnmanagedVector*);
} Iterator_vtable;
typedef struct GoIter {
diff --git a/internal/api/callbacks.go b/internal/api/callbacks.go
index 0f0cdcce9..66e96836a 100644
--- a/internal/api/callbacks.go
+++ b/internal/api/callbacks.go
@@ -13,6 +13,8 @@ typedef GoError (*remove_db_fn)(db_t *ptr, gas_meter_t *gas_meter, uint64_t *use
typedef GoError (*scan_db_fn)(db_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, U8SliceView start, U8SliceView end, int32_t order, GoIter *out, UnmanagedVector *errOut);
// iterator
typedef GoError (*next_db_fn)(iterator_t idx, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *val, UnmanagedVector *errOut);
+typedef GoError (*next_key_db_fn)(iterator_t idx, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *errOut);
+typedef GoError (*next_value_db_fn)(iterator_t idx, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *val, UnmanagedVector *errOut);
// and api
typedef GoError (*humanize_address_fn)(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
typedef GoError (*canonicalize_address_fn)(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
@@ -25,6 +27,8 @@ GoError cDelete_cgo(db_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, U8Sli
GoError cScan_cgo(db_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, U8SliceView start, U8SliceView end, int32_t order, GoIter *out, UnmanagedVector *errOut);
// iterator
GoError cNext_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *val, UnmanagedVector *errOut);
+GoError cNextKey_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *errOut);
+GoError cNextValue_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *val, UnmanagedVector *errOut);
// api
GoError cHumanAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
GoError cCanonicalAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
@@ -128,7 +132,9 @@ func buildDB(state *DBState, gm *types.GasMeter) C.Db {
}
var iterator_vtable = C.Iterator_vtable{
- next_db: (C.next_db_fn)(C.cNext_cgo),
+ next_db: (C.next_db_fn)(C.cNext_cgo),
+ next_key_db: (C.next_key_db_fn)(C.cNextKey_cgo),
+ next_value_db: (C.next_value_db_fn)(C.cNextValue_cgo),
}
// An iterator including referenced objects is 117 bytes large (calculated using https://github.com/DmitriyVTitov/size).
@@ -310,6 +316,55 @@ func cNext(ref C.iterator_t, gasMeter *C.gas_meter_t, usedGas *cu64, key *C.Unma
return C.GoError_None
}
+//export cNextKey
+func cNextKey(ref C.iterator_t, gasMeter *C.gas_meter_t, usedGas *cu64, key *C.UnmanagedVector, errOut *C.UnmanagedVector) (ret C.GoError) {
+ return nextPart(ref, gasMeter, usedGas, key, errOut, func(iter types.Iterator) []byte { return iter.Key() })
+}
+
+//export cNextValue
+func cNextValue(ref C.iterator_t, gasMeter *C.gas_meter_t, usedGas *cu64, value *C.UnmanagedVector, errOut *C.UnmanagedVector) (ret C.GoError) {
+ return nextPart(ref, gasMeter, usedGas, value, errOut, func(iter types.Iterator) []byte { return iter.Value() })
+}
+
+// nextPart is a helper function that contains the shared code for key- and value-only iteration.
+func nextPart(ref C.iterator_t, gasMeter *C.gas_meter_t, usedGas *cu64, output *C.UnmanagedVector, errOut *C.UnmanagedVector, valFn func(types.Iterator) []byte) (ret C.GoError) {
+ // typical usage of iterator
+ // for ; itr.Valid(); itr.Next() {
+ // k, v := itr.Key(); itr.Value()
+ // ...
+ // }
+
+ defer recoverPanic(&ret)
+ if ref.call_id == 0 || gasMeter == nil || usedGas == nil || output == nil || errOut == nil {
+ // we received an invalid pointer
+ return C.GoError_BadArgument
+ }
+ if !(*output).is_none || !(*errOut).is_none {
+ panic("Got a non-none UnmanagedVector we're about to override. This is a bug because someone has to drop the old one.")
+ }
+
+ gm := *(*types.GasMeter)(unsafe.Pointer(gasMeter))
+ iter := retrieveIterator(uint64(ref.call_id), uint64(ref.iterator_index))
+ if iter == nil {
+ panic("Unable to retrieve iterator.")
+ }
+ if !iter.Valid() {
+ // end of iterator, return as no-op, nil key is considered end
+ return C.GoError_None
+ }
+
+ gasBefore := gm.GasConsumed()
+ // call Next at the end, upon creation we have first data loaded
+ out := valFn(iter)
+ // check iter.Error() ????
+ iter.Next()
+ gasAfter := gm.GasConsumed()
+ *usedGas = (cu64)(gasAfter - gasBefore)
+
+ *output = newUnmanagedVector(out)
+ return C.GoError_None
+}
+
var api_vtable = C.GoApi_vtable{
humanize_address: (C.humanize_address_fn)(C.cHumanAddress_cgo),
canonicalize_address: (C.canonicalize_address_fn)(C.cCanonicalAddress_cgo),
diff --git a/internal/api/callbacks_cgo.go b/internal/api/callbacks_cgo.go
index 6cc036324..343c890a9 100644
--- a/internal/api/callbacks_cgo.go
+++ b/internal/api/callbacks_cgo.go
@@ -11,6 +11,8 @@ GoError cDelete(db_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, U8SliceVi
GoError cScan(db_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, U8SliceView start, U8SliceView end, int32_t order, GoIter *out, UnmanagedVector *errOut);
// imports (iterator)
GoError cNext(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *val, UnmanagedVector *errOut);
+GoError cNextKey(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *errOut);
+GoError cNextValue(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *value, UnmanagedVector *errOut);
// imports (api)
GoError cHumanAddress(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
GoError cCanonicalAddress(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas);
@@ -35,6 +37,12 @@ GoError cScan_cgo(db_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, U8Slice
GoError cNext_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *val, UnmanagedVector *errOut) {
return cNext(ptr, gas_meter, used_gas, key, val, errOut);
}
+GoError cNextKey_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *key, UnmanagedVector *errOut) {
+ return cNextKey(ptr, gas_meter, used_gas, key, errOut);
+}
+GoError cNextValue_cgo(iterator_t *ptr, gas_meter_t *gas_meter, uint64_t *used_gas, UnmanagedVector *val, UnmanagedVector *errOut) {
+ return cNextValue(ptr, gas_meter, used_gas, val, errOut);
+}
// Gateway functions (api)
GoError cCanonicalAddress_cgo(api_t *ptr, U8SliceView src, UnmanagedVector *dest, UnmanagedVector *errOut, uint64_t *used_gas) {
diff --git a/internal/api/libwasmvm.dylib b/internal/api/libwasmvm.dylib
index a34a04202..7ee59b39f 100755
Binary files a/internal/api/libwasmvm.dylib and b/internal/api/libwasmvm.dylib differ
diff --git a/libwasmvm/bindings.h b/libwasmvm/bindings.h
index 5b38b7736..a2e9950a9 100644
--- a/libwasmvm/bindings.h
+++ b/libwasmvm/bindings.h
@@ -260,6 +260,16 @@ typedef struct Iterator_vtable {
struct UnmanagedVector*,
struct UnmanagedVector*,
struct UnmanagedVector*);
+ int32_t (*next_key_db)(struct iterator_t,
+ struct gas_meter_t*,
+ uint64_t*,
+ struct UnmanagedVector*,
+ struct UnmanagedVector*);
+ int32_t (*next_value_db)(struct iterator_t,
+ struct gas_meter_t*,
+ uint64_t*,
+ struct UnmanagedVector*,
+ struct UnmanagedVector*);
} Iterator_vtable;
typedef struct GoIter {
diff --git a/libwasmvm/src/iterator.rs b/libwasmvm/src/iterator.rs
index 565b9d1d6..81c9cc26f 100644
--- a/libwasmvm/src/iterator.rs
+++ b/libwasmvm/src/iterator.rs
@@ -29,6 +29,24 @@ pub struct Iterator_vtable {
*mut UnmanagedVector, // error message output
) -> i32,
>,
+ pub next_key_db: Option<
+ extern "C" fn(
+ iterator_t,
+ *mut gas_meter_t,
+ *mut u64,
+ *mut UnmanagedVector, // key output
+ *mut UnmanagedVector, // error message output
+ ) -> i32,
+ >,
+ pub next_value_db: Option<
+ extern "C" fn(
+ iterator_t,
+ *mut gas_meter_t,
+ *mut u64,
+ *mut UnmanagedVector, // value output
+ *mut UnmanagedVector, // error message output
+ ) -> i32,
+ >,
}
#[repr(C)]
@@ -97,4 +115,60 @@ impl GoIter {
};
(result, gas_info)
}
+
+ pub fn next_key(&mut self) -> BackendResult