From d9122b53bb3635aafb8a67902c0067a9a76d9adc Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Fri, 23 Jan 2026 20:18:23 +0100 Subject: [PATCH] Add PEL collection view projection --- CMakeLists.txt | 6 +- include/amduat/asl/collection.h | 13 + include/amduat/asl/collection_view.h | 74 +++ include/amduat/asl/log_store.h | 16 + include/amduat/asl/none.h | 27 ++ include/amduat/pel/opreg_kernel.h | 37 +- src/core/asl_collection.c | 124 +++++ src/core/asl_log_store.c | 19 +- src/near_core/asl/collection_view.c | 520 ++++++++++++++++++++ src/near_core/asl/none.c | 110 +++++ src/near_core/format/pel.c | 10 + src/pel_stack/opreg/kernel.c | 70 +++ src/pel_stack/opreg/kernel_collection.c | 615 ++++++++++++++++++++++++ src/pel_stack/opreg/kernel_collection.h | 29 ++ src/pel_stack/opreg/kernel_params.c | 6 + src/pel_stack/surf/surf.c | 16 + src/tools/amduat_pel_cli.c | 521 +++++++++++++++++++- 17 files changed, 2194 insertions(+), 19 deletions(-) create mode 100644 include/amduat/asl/collection_view.h create mode 100644 include/amduat/asl/none.h create mode 100644 src/near_core/asl/collection_view.c create mode 100644 src/near_core/asl/none.c create mode 100644 src/pel_stack/opreg/kernel_collection.c create mode 100644 src/pel_stack/opreg/kernel_collection.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e2b649d..e2061e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ set(AMDUAT_UTIL_SRCS set(AMDUAT_ASL_SRCS src/kernel/asl/core.c + src/near_core/asl/collection_view.c + src/near_core/asl/none.c src/near_core/asl/artifact_io.c src/near_core/asl/io.c src/near_core/asl/index_accel.c @@ -127,6 +129,7 @@ set(AMDUAT_PEL_SRCS src/pel_stack/trace_dag/trace_dag.c src/pel_stack/queue/queue.c src/pel_stack/opreg/kernel.c + src/pel_stack/opreg/kernel_collection.c src/pel_stack/opreg/kernel_params.c ) @@ -193,7 +196,8 @@ amduat_add_lib(format SRCS ${AMDUAT_FORMAT_SRCS}) amduat_link(format amduat_asl amduat_enc amduat_util) amduat_add_lib(pel SRCS ${AMDUAT_PEL_SRCS}) -amduat_link(pel amduat_asl_materialization_cache_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util) +amduat_link(pel amduat_asl_materialization_cache_fs amduat_asl_collection + amduat_asl amduat_enc amduat_hash_asl1 amduat_util) amduat_add_lib(tgk SRCS ${AMDUAT_TGK_SRCS}) amduat_link(tgk amduat_asl amduat_enc amduat_hash_asl1 amduat_util) diff --git a/include/amduat/asl/collection.h b/include/amduat/asl/collection.h index 3145e40..728e382 100644 --- a/include/amduat/asl/collection.h +++ b/include/amduat/asl/collection.h @@ -28,6 +28,12 @@ typedef struct { amduat_asl_pointer_store_t pointer_store; } amduat_asl_collection_store_t; +typedef struct { + uint64_t snapshot_offset; + amduat_reference_t *refs; + size_t refs_len; +} amduat_asl_collection_snapshot_payload_t; + bool amduat_asl_collection_store_init( amduat_asl_collection_store_t *collection_store, const char *root_path, @@ -61,6 +67,13 @@ amduat_asl_collection_error_t amduat_asl_collection_read( void amduat_asl_collection_refs_free(amduat_reference_t *refs, size_t refs_len); +bool amduat_asl_collection_snapshot_payload_decode_v1( + amduat_octets_t payload, + amduat_asl_collection_snapshot_payload_t *out_snapshot); + +void amduat_asl_collection_snapshot_payload_free( + amduat_asl_collection_snapshot_payload_t *snapshot); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/amduat/asl/collection_view.h b/include/amduat/asl/collection_view.h new file mode 100644 index 0000000..3fe3ff0 --- /dev/null +++ b/include/amduat/asl/collection_view.h @@ -0,0 +1,74 @@ +#ifndef AMDUAT_ASL_COLLECTION_VIEW_H +#define AMDUAT_ASL_COLLECTION_VIEW_H + +#include "amduat/asl/core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { TYPE_TAG_ASL_COLLECTION_VIEW_1 = 0x00000403u }; +enum { AMDUAT_TYPE_TAG_ASL_COLLECTION_VIEW_1 = TYPE_TAG_ASL_COLLECTION_VIEW_1 }; +enum { TYPE_TAG_ASL_SNAPSHOT_INFO_1 = 0x00000405u }; +enum { AMDUAT_TYPE_TAG_ASL_SNAPSHOT_INFO_1 = TYPE_TAG_ASL_SNAPSHOT_INFO_1 }; +enum { TYPE_TAG_ASL_LOG_RANGE_1 = 0x00000406u }; +enum { AMDUAT_TYPE_TAG_ASL_LOG_RANGE_1 = TYPE_TAG_ASL_LOG_RANGE_1 }; + +typedef struct { + uint64_t snapshot_at_offset; + amduat_reference_t *refs; + size_t refs_len; +} amduat_asl_collection_snapshot_info_t; + +typedef struct { + uint64_t start_offset; + uint64_t next_offset; + amduat_reference_t *refs; + size_t refs_len; +} amduat_asl_log_range_t; + +typedef struct { + uint64_t computed_from_offset; + uint64_t computed_up_to_offset; + amduat_reference_t *refs; + size_t refs_len; +} amduat_asl_collection_view_t; + +bool amduat_asl_collection_snapshot_info_encode_v1( + const amduat_asl_collection_snapshot_info_t *info, + amduat_octets_t *out_bytes); + +bool amduat_asl_collection_snapshot_info_decode_v1( + amduat_octets_t bytes, + amduat_asl_collection_snapshot_info_t *out_info); + +void amduat_asl_collection_snapshot_info_free( + amduat_asl_collection_snapshot_info_t *info); + +bool amduat_asl_log_range_encode_v1(const amduat_asl_log_range_t *range, + amduat_octets_t *out_bytes); + +bool amduat_asl_log_range_decode_v1(amduat_octets_t bytes, + amduat_asl_log_range_t *out_range); + +void amduat_asl_log_range_free(amduat_asl_log_range_t *range); + +bool amduat_asl_collection_view_encode_v1( + const amduat_asl_collection_view_t *view, + amduat_octets_t *out_bytes); + +bool amduat_asl_collection_view_decode_v1( + amduat_octets_t bytes, + amduat_asl_collection_view_t *out_view); + +void amduat_asl_collection_view_free(amduat_asl_collection_view_t *view); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_ASL_COLLECTION_VIEW_H */ diff --git a/include/amduat/asl/log_store.h b/include/amduat/asl/log_store.h index 5dab443..b02ef04 100644 --- a/include/amduat/asl/log_store.h +++ b/include/amduat/asl/log_store.h @@ -25,6 +25,16 @@ typedef struct { amduat_octets_t actor; } amduat_asl_log_entry_t; +typedef struct { + bool has_prev; + amduat_reference_t prev_ref; + uint64_t base_offset; + uint32_t entry_count; + bool has_timestamp; + bool has_actor; + amduat_asl_log_entry_t *entries; +} amduat_asl_log_chunk_t; + typedef struct { amduat_asl_store_t *store; amduat_asl_pointer_store_t pointer_store; @@ -55,6 +65,12 @@ amduat_asl_store_error_t amduat_asl_log_read( void amduat_asl_log_entries_free(amduat_asl_log_entry_t *entries, size_t entries_len); +amduat_asl_store_error_t amduat_asl_log_chunk_decode_v1( + amduat_octets_t bytes, + amduat_asl_log_chunk_t *out_chunk); + +void amduat_asl_log_chunk_free(amduat_asl_log_chunk_t *chunk); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/amduat/asl/none.h b/include/amduat/asl/none.h new file mode 100644 index 0000000..5cb1064 --- /dev/null +++ b/include/amduat/asl/none.h @@ -0,0 +1,27 @@ +#ifndef AMDUAT_ASL_NONE_H +#define AMDUAT_ASL_NONE_H + +#include "amduat/asl/core.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { TYPE_TAG_ASL_NONE_1 = 0x00000404u }; +enum { AMDUAT_TYPE_TAG_ASL_NONE_1 = TYPE_TAG_ASL_NONE_1 }; + +bool amduat_asl_none_encode_v1(amduat_octets_t *out_bytes); + +bool amduat_asl_none_decode_v1(amduat_octets_t bytes); + +bool amduat_asl_none_is_artifact(const amduat_artifact_t *artifact); + +bool amduat_asl_none_artifact(amduat_artifact_t *out_artifact); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_ASL_NONE_H */ diff --git a/include/amduat/pel/opreg_kernel.h b/include/amduat/pel/opreg_kernel.h index e00b23f..f223b58 100644 --- a/include/amduat/pel/opreg_kernel.h +++ b/include/amduat/pel/opreg_kernel.h @@ -17,6 +17,11 @@ extern "C" { #define AMDUAT_PEL_KERNEL_OP_HASH_ASL1_NAME "pel.bytes.hash.asl1" #define AMDUAT_PEL_KERNEL_OP_PARAMS_NAME "pel.bytes.params" #define AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE_NAME "pel.format.encode" +#define AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE_NAME \ + "collection.snapshot_decode_v1" +#define AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE_NAME "log.read_range_v1" +#define AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS_NAME \ + "collection.merge_refs_v1" enum { AMDUAT_PEL_KERNEL_OP_CODE_CONCAT = 0x0001u, @@ -24,7 +29,10 @@ enum { AMDUAT_PEL_KERNEL_OP_CODE_CONST = 0x0003u, AMDUAT_PEL_KERNEL_OP_CODE_HASH_ASL1 = 0x0004u, AMDUAT_PEL_KERNEL_OP_CODE_PARAMS = 0x0005u, - AMDUAT_PEL_KERNEL_OP_CODE_FORMAT_ENCODE = 0x0006u + AMDUAT_PEL_KERNEL_OP_CODE_FORMAT_ENCODE = 0x0006u, + AMDUAT_PEL_KERNEL_OP_CODE_COLLECTION_SNAPSHOT_DECODE = 0x0007u, + AMDUAT_PEL_KERNEL_OP_CODE_LOG_READ_RANGE = 0x0008u, + AMDUAT_PEL_KERNEL_OP_CODE_COLLECTION_MERGE_REFS = 0x0009u }; enum { @@ -35,7 +43,13 @@ enum { AMDUAT_PEL_KERNEL_STATUS_FORMAT_SCHEMA_INVALID = 0x00030001u, AMDUAT_PEL_KERNEL_STATUS_FORMAT_REGISTRY_INVALID = 0x00030002u, AMDUAT_PEL_KERNEL_STATUS_FORMAT_MISSING_FIELD = 0x00030003u, - AMDUAT_PEL_KERNEL_STATUS_FORMAT_TYPE_UNSUPPORTED = 0x00030004u + AMDUAT_PEL_KERNEL_STATUS_FORMAT_TYPE_UNSUPPORTED = 0x00030004u, + AMDUAT_PEL_KERNEL_STATUS_PARAMS_INVALID = 0x00040001u, + AMDUAT_PEL_KERNEL_STATUS_COLLECTION_SNAPSHOT_INVALID = 0x00040002u, + AMDUAT_PEL_KERNEL_STATUS_LOG_CHUNK_INVALID = 0x00040003u, + AMDUAT_PEL_KERNEL_STATUS_LOG_RANGE_INVALID = 0x00040004u, + AMDUAT_PEL_KERNEL_STATUS_COLLECTION_VIEW_INVALID = 0x00040005u, + AMDUAT_PEL_KERNEL_STATUS_REF_RESOLVE_FAILED = 0x00040006u }; typedef enum { @@ -44,7 +58,10 @@ typedef enum { AMDUAT_PEL_KERNEL_OP_CONST = 3, AMDUAT_PEL_KERNEL_OP_HASH_ASL1 = 4, AMDUAT_PEL_KERNEL_OP_PARAMS = 5, - AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE = 6 + AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE = 6, + AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE = 7, + AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE = 8, + AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS = 9 } amduat_pel_kernel_op_kind_t; typedef struct { @@ -58,6 +75,11 @@ typedef struct { struct amduat_pel_kernel_params; typedef struct amduat_pel_kernel_params amduat_pel_kernel_params_t; +typedef bool (*amduat_pel_kernel_artifact_resolver_t)( + amduat_reference_t ref, + amduat_artifact_t *out_artifact, + void *ctx); + const amduat_pel_kernel_op_desc_t *amduat_pel_kernel_op_lookup( amduat_octets_t name, uint32_t version); @@ -67,6 +89,15 @@ const amduat_pel_kernel_op_desc_t *amduat_pel_kernel_op_descs( const char *amduat_pel_kernel_op_name(amduat_pel_kernel_op_kind_t kind); +void amduat_pel_kernel_set_artifact_resolver( + amduat_pel_kernel_artifact_resolver_t resolver, + void *ctx); + +void amduat_pel_kernel_clear_artifact_resolver(void); + +bool amduat_pel_kernel_resolve_artifact(amduat_reference_t ref, + amduat_artifact_t *out_artifact); + bool amduat_pel_kernel_op_eval( const amduat_pel_kernel_op_desc_t *desc, const amduat_artifact_t *inputs, diff --git a/src/core/asl_collection.c b/src/core/asl_collection.c index 6a8b738..849a23a 100644 --- a/src/core/asl_collection.c +++ b/src/core/asl_collection.c @@ -36,6 +36,40 @@ static void amduat_asl_collection_store_u64_le(uint8_t *out, uint64_t value) { out[7] = (uint8_t)((value >> 56) & 0xffu); } +static bool amduat_asl_collection_read_u32_le(const uint8_t *data, + size_t len, + size_t *offset, + uint32_t *out) { + if (len - *offset < 4u) { + return false; + } + *out = (uint32_t)data[*offset] | + ((uint32_t)data[*offset + 1u] << 8) | + ((uint32_t)data[*offset + 2u] << 16) | + ((uint32_t)data[*offset + 3u] << 24); + *offset += 4u; + return true; +} + +static bool amduat_asl_collection_read_u64_le(const uint8_t *data, + size_t len, + size_t *offset, + uint64_t *out) { + if (len - *offset < 8u) { + return false; + } + *out = (uint64_t)data[*offset] | + ((uint64_t)data[*offset + 1u] << 8) | + ((uint64_t)data[*offset + 2u] << 16) | + ((uint64_t)data[*offset + 3u] << 24) | + ((uint64_t)data[*offset + 4u] << 32) | + ((uint64_t)data[*offset + 5u] << 40) | + ((uint64_t)data[*offset + 6u] << 48) | + ((uint64_t)data[*offset + 7u] << 56); + *offset += 8u; + return true; +} + static bool amduat_asl_collection_add_size(size_t *acc, size_t add) { if (*acc > SIZE_MAX - add) { return false; @@ -481,3 +515,93 @@ void amduat_asl_collection_refs_free(amduat_reference_t *refs, } free(refs); } + +bool amduat_asl_collection_snapshot_payload_decode_v1( + amduat_octets_t payload, + amduat_asl_collection_snapshot_payload_t *out_snapshot) { + size_t offset = 0u; + uint32_t version = 0u; + uint32_t entry_count = 0u; + + if (out_snapshot == NULL) { + return false; + } + out_snapshot->snapshot_offset = 0u; + out_snapshot->refs = NULL; + out_snapshot->refs_len = 0u; + + if (payload.len < AMDUAT_ASL_COLLECTION_MAGIC_LEN + 4u + 8u + 4u) { + return false; + } + if (payload.data == NULL) { + return false; + } + if (memcmp(payload.data, k_amduat_asl_collection_magic, + AMDUAT_ASL_COLLECTION_MAGIC_LEN) != 0) { + return false; + } + offset += AMDUAT_ASL_COLLECTION_MAGIC_LEN; + if (!amduat_asl_collection_read_u32_le(payload.data, payload.len, + &offset, &version) || + version != AMDUAT_ASL_COLLECTION_VERSION) { + return false; + } + if (!amduat_asl_collection_read_u64_le(payload.data, payload.len, + &offset, + &out_snapshot->snapshot_offset)) { + return false; + } + if (!amduat_asl_collection_read_u32_le(payload.data, payload.len, + &offset, &entry_count)) { + return false; + } + if (entry_count == 0u) { + return offset == payload.len; + } + if (entry_count > SIZE_MAX / sizeof(amduat_reference_t)) { + return false; + } + out_snapshot->refs = + (amduat_reference_t *)calloc(entry_count, sizeof(*out_snapshot->refs)); + if (out_snapshot->refs == NULL) { + return false; + } + out_snapshot->refs_len = entry_count; + + for (uint32_t i = 0u; i < entry_count; ++i) { + uint32_t ref_len = 0u; + amduat_octets_t ref_bytes; + if (!amduat_asl_collection_read_u32_le(payload.data, payload.len, + &offset, &ref_len)) { + goto fail; + } + if (payload.len - offset < ref_len) { + goto fail; + } + ref_bytes = amduat_octets(payload.data + offset, ref_len); + if (!amduat_enc_asl1_core_decode_reference_v1( + ref_bytes, &out_snapshot->refs[i])) { + goto fail; + } + offset += ref_len; + } + + return offset == payload.len; + +fail: + amduat_asl_collection_snapshot_payload_free(out_snapshot); + return false; +} + +void amduat_asl_collection_snapshot_payload_free( + amduat_asl_collection_snapshot_payload_t *snapshot) { + if (snapshot == NULL || snapshot->refs == NULL) { + return; + } + for (size_t i = 0u; i < snapshot->refs_len; ++i) { + amduat_reference_free(&snapshot->refs[i]); + } + free(snapshot->refs); + snapshot->refs = NULL; + snapshot->refs_len = 0u; +} diff --git a/src/core/asl_log_store.c b/src/core/asl_log_store.c index 6933901..78e4fe0 100644 --- a/src/core/asl_log_store.c +++ b/src/core/asl_log_store.c @@ -25,16 +25,6 @@ enum { AMDUAT_ASL_LOG_FLAG_HAS_ACTOR = 1u << 2 }; -typedef struct { - bool has_prev; - amduat_reference_t prev_ref; - uint64_t base_offset; - uint32_t entry_count; - bool has_timestamp; - bool has_actor; - amduat_asl_log_entry_t *entries; -} amduat_asl_log_chunk_t; - typedef struct { const uint8_t *data; size_t len; @@ -115,7 +105,7 @@ static bool amduat_asl_log_add_size(size_t *acc, size_t add) { return true; } -static void amduat_asl_log_chunk_free(amduat_asl_log_chunk_t *chunk) { +void amduat_asl_log_chunk_free(amduat_asl_log_chunk_t *chunk) { if (chunk == NULL) { return; } @@ -342,7 +332,7 @@ cleanup: return AMDUAT_ASL_STORE_ERR_INTEGRITY; } -static amduat_asl_store_error_t amduat_asl_log_decode_chunk( +amduat_asl_store_error_t amduat_asl_log_chunk_decode_v1( amduat_octets_t bytes, amduat_asl_log_chunk_t *out_chunk) { amduat_asl_log_cursor_t cur; @@ -574,7 +564,8 @@ amduat_asl_store_error_t amduat_asl_log_append( free(pointer_name); return AMDUAT_ASL_STORE_ERR_INTEGRITY; } - store_err = amduat_asl_log_decode_chunk(head_artifact.bytes, &head_chunk); + store_err = amduat_asl_log_chunk_decode_v1(head_artifact.bytes, + &head_chunk); amduat_artifact_free(&head_artifact); if (store_err != AMDUAT_ASL_STORE_OK) { amduat_reference_free(&head_ref); @@ -744,7 +735,7 @@ amduat_asl_store_error_t amduat_asl_log_read( amduat_reference_free(&head_ref); return AMDUAT_ASL_STORE_ERR_INTEGRITY; } - err = amduat_asl_log_decode_chunk(artifact.bytes, &chunk); + err = amduat_asl_log_chunk_decode_v1(artifact.bytes, &chunk); amduat_artifact_free(&artifact); if (err != AMDUAT_ASL_STORE_OK) { if (current_ref_owned) { diff --git a/src/near_core/asl/collection_view.c b/src/near_core/asl/collection_view.c new file mode 100644 index 0000000..1cf4485 --- /dev/null +++ b/src/near_core/asl/collection_view.c @@ -0,0 +1,520 @@ +#include "amduat/asl/collection_view.h" + +#include "amduat/enc/asl1_core_codec.h" + +#include +#include +#include + +enum { + AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN = 8, + AMDUAT_ASL_COLLECTION_VIEW_VERSION = 1, + AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN = 8, + AMDUAT_ASL_SNAPSHOT_INFO_VERSION = 1, + AMDUAT_ASL_LOG_RANGE_MAGIC_LEN = 8, + AMDUAT_ASL_LOG_RANGE_VERSION = 1 +}; + +static const uint8_t k_amduat_asl_collection_view_magic[ + AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN] = { + 'A', 'S', 'L', 'C', 'V', 'W', '1', '\0' +}; + +static const uint8_t k_amduat_asl_snapshot_info_magic[ + AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN] = { + 'A', 'S', 'L', 'S', 'N', 'P', '1', '\0' +}; + +static const uint8_t k_amduat_asl_log_range_magic[ + AMDUAT_ASL_LOG_RANGE_MAGIC_LEN] = { + 'A', 'S', 'L', 'R', 'N', 'G', '1', '\0' +}; + +static void amduat_asl_store_u32_le(uint8_t *out, uint32_t value) { + out[0] = (uint8_t)(value & 0xffu); + out[1] = (uint8_t)((value >> 8) & 0xffu); + out[2] = (uint8_t)((value >> 16) & 0xffu); + out[3] = (uint8_t)((value >> 24) & 0xffu); +} + +static void amduat_asl_store_u64_le(uint8_t *out, uint64_t value) { + out[0] = (uint8_t)(value & 0xffu); + out[1] = (uint8_t)((value >> 8) & 0xffu); + out[2] = (uint8_t)((value >> 16) & 0xffu); + out[3] = (uint8_t)((value >> 24) & 0xffu); + out[4] = (uint8_t)((value >> 32) & 0xffu); + out[5] = (uint8_t)((value >> 40) & 0xffu); + out[6] = (uint8_t)((value >> 48) & 0xffu); + out[7] = (uint8_t)((value >> 56) & 0xffu); +} + +static bool amduat_asl_read_u32_le(const uint8_t *data, + size_t len, + size_t *offset, + uint32_t *out) { + if (len - *offset < 4u) { + return false; + } + *out = (uint32_t)data[*offset] | + ((uint32_t)data[*offset + 1u] << 8) | + ((uint32_t)data[*offset + 2u] << 16) | + ((uint32_t)data[*offset + 3u] << 24); + *offset += 4u; + return true; +} + +static bool amduat_asl_read_u64_le(const uint8_t *data, + size_t len, + size_t *offset, + uint64_t *out) { + if (len - *offset < 8u) { + return false; + } + *out = (uint64_t)data[*offset] | + ((uint64_t)data[*offset + 1u] << 8) | + ((uint64_t)data[*offset + 2u] << 16) | + ((uint64_t)data[*offset + 3u] << 24) | + ((uint64_t)data[*offset + 4u] << 32) | + ((uint64_t)data[*offset + 5u] << 40) | + ((uint64_t)data[*offset + 6u] << 48) | + ((uint64_t)data[*offset + 7u] << 56); + *offset += 8u; + return true; +} + +static bool amduat_asl_add_size(size_t *acc, size_t add) { + if (*acc > SIZE_MAX - add) { + return false; + } + *acc += add; + return true; +} + +static bool amduat_asl_encode_refs(const amduat_reference_t *refs, + size_t refs_len, + size_t *out_total_len) { + size_t total = 0u; + + if (refs_len > UINT32_MAX) { + return false; + } + for (size_t i = 0u; i < refs_len; ++i) { + amduat_octets_t ref_bytes = amduat_octets(NULL, 0u); + if (!amduat_enc_asl1_core_encode_reference_v1(refs[i], &ref_bytes)) { + return false; + } + if (!amduat_asl_add_size(&total, 4u + ref_bytes.len)) { + free((void *)ref_bytes.data); + return false; + } + free((void *)ref_bytes.data); + } + *out_total_len = total; + return true; +} + +static bool amduat_asl_write_refs(uint8_t *buffer, + size_t total_len, + size_t *offset, + const amduat_reference_t *refs, + size_t refs_len) { + for (size_t i = 0u; i < refs_len; ++i) { + amduat_octets_t ref_bytes = amduat_octets(NULL, 0u); + if (!amduat_enc_asl1_core_encode_reference_v1(refs[i], &ref_bytes)) { + return false; + } + if (total_len - *offset < 4u + ref_bytes.len) { + free((void *)ref_bytes.data); + return false; + } + amduat_asl_store_u32_le(buffer + *offset, (uint32_t)ref_bytes.len); + *offset += 4u; + memcpy(buffer + *offset, ref_bytes.data, ref_bytes.len); + *offset += ref_bytes.len; + free((void *)ref_bytes.data); + } + return true; +} + +static bool amduat_asl_decode_refs(amduat_octets_t bytes, + size_t *offset, + uint32_t refs_len, + amduat_reference_t **out_refs, + size_t *out_refs_len) { + amduat_reference_t *refs = NULL; + + if (out_refs == NULL || out_refs_len == NULL) { + return false; + } + *out_refs = NULL; + *out_refs_len = 0u; + + if (refs_len == 0u) { + return true; + } + if (refs_len > SIZE_MAX / sizeof(*refs)) { + return false; + } + refs = (amduat_reference_t *)calloc(refs_len, sizeof(*refs)); + if (refs == NULL) { + return false; + } + + for (uint32_t i = 0u; i < refs_len; ++i) { + uint32_t ref_len = 0u; + amduat_octets_t ref_bytes; + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, offset, &ref_len)) { + goto fail; + } + if (bytes.len - *offset < ref_len) { + goto fail; + } + ref_bytes = amduat_octets(bytes.data + *offset, ref_len); + if (!amduat_enc_asl1_core_decode_reference_v1(ref_bytes, &refs[i])) { + goto fail; + } + *offset += ref_len; + } + + *out_refs = refs; + *out_refs_len = refs_len; + return true; + +fail: + for (uint32_t i = 0u; i < refs_len; ++i) { + amduat_reference_free(&refs[i]); + } + free(refs); + return false; +} + +bool amduat_asl_collection_snapshot_info_encode_v1( + const amduat_asl_collection_snapshot_info_t *info, + amduat_octets_t *out_bytes) { + uint8_t *buffer; + size_t total_len = 0u; + size_t refs_len_bytes = 0u; + size_t offset = 0u; + + if (out_bytes == NULL || info == NULL) { + return false; + } + out_bytes->data = NULL; + out_bytes->len = 0u; + + if (!amduat_asl_add_size(&total_len, + AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN + 4u + 8u + 4u)) { + return false; + } + if (!amduat_asl_encode_refs(info->refs, info->refs_len, &refs_len_bytes)) { + return false; + } + if (!amduat_asl_add_size(&total_len, refs_len_bytes)) { + return false; + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + memcpy(buffer + offset, k_amduat_asl_snapshot_info_magic, + AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN); + offset += AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN; + amduat_asl_store_u32_le(buffer + offset, AMDUAT_ASL_SNAPSHOT_INFO_VERSION); + offset += 4u; + amduat_asl_store_u64_le(buffer + offset, info->snapshot_at_offset); + offset += 8u; + amduat_asl_store_u32_le(buffer + offset, (uint32_t)info->refs_len); + offset += 4u; + if (!amduat_asl_write_refs(buffer, total_len, &offset, + info->refs, info->refs_len)) { + free(buffer); + return false; + } + + if (offset != total_len) { + free(buffer); + return false; + } + *out_bytes = amduat_octets(buffer, total_len); + return true; +} + +bool amduat_asl_collection_snapshot_info_decode_v1( + amduat_octets_t bytes, + amduat_asl_collection_snapshot_info_t *out_info) { + size_t offset = 0u; + uint32_t version = 0u; + uint32_t refs_len = 0u; + + if (out_info == NULL) { + return false; + } + out_info->snapshot_at_offset = 0u; + out_info->refs = NULL; + out_info->refs_len = 0u; + + if (bytes.len < AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN + 4u + 8u + 4u || + bytes.data == NULL) { + return false; + } + if (memcmp(bytes.data, k_amduat_asl_snapshot_info_magic, + AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN) != 0) { + return false; + } + offset += AMDUAT_ASL_SNAPSHOT_INFO_MAGIC_LEN; + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, &offset, &version) || + version != AMDUAT_ASL_SNAPSHOT_INFO_VERSION) { + return false; + } + if (!amduat_asl_read_u64_le(bytes.data, bytes.len, &offset, + &out_info->snapshot_at_offset)) { + return false; + } + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, &offset, &refs_len)) { + return false; + } + if (!amduat_asl_decode_refs(bytes, &offset, refs_len, + &out_info->refs, &out_info->refs_len)) { + return false; + } + return offset == bytes.len; +} + +void amduat_asl_collection_snapshot_info_free( + amduat_asl_collection_snapshot_info_t *info) { + if (info == NULL || info->refs == NULL) { + return; + } + for (size_t i = 0u; i < info->refs_len; ++i) { + amduat_reference_free(&info->refs[i]); + } + free(info->refs); + info->refs = NULL; + info->refs_len = 0u; +} + +bool amduat_asl_log_range_encode_v1(const amduat_asl_log_range_t *range, + amduat_octets_t *out_bytes) { + uint8_t *buffer; + size_t total_len = 0u; + size_t refs_len_bytes = 0u; + size_t offset = 0u; + + if (out_bytes == NULL || range == NULL) { + return false; + } + out_bytes->data = NULL; + out_bytes->len = 0u; + + if (!amduat_asl_add_size(&total_len, + AMDUAT_ASL_LOG_RANGE_MAGIC_LEN + 4u + 8u + 8u + 4u)) { + return false; + } + if (!amduat_asl_encode_refs(range->refs, range->refs_len, &refs_len_bytes)) { + return false; + } + if (!amduat_asl_add_size(&total_len, refs_len_bytes)) { + return false; + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + memcpy(buffer + offset, k_amduat_asl_log_range_magic, + AMDUAT_ASL_LOG_RANGE_MAGIC_LEN); + offset += AMDUAT_ASL_LOG_RANGE_MAGIC_LEN; + amduat_asl_store_u32_le(buffer + offset, AMDUAT_ASL_LOG_RANGE_VERSION); + offset += 4u; + amduat_asl_store_u64_le(buffer + offset, range->start_offset); + offset += 8u; + amduat_asl_store_u64_le(buffer + offset, range->next_offset); + offset += 8u; + amduat_asl_store_u32_le(buffer + offset, (uint32_t)range->refs_len); + offset += 4u; + if (!amduat_asl_write_refs(buffer, total_len, &offset, + range->refs, range->refs_len)) { + free(buffer); + return false; + } + + if (offset != total_len) { + free(buffer); + return false; + } + *out_bytes = amduat_octets(buffer, total_len); + return true; +} + +bool amduat_asl_log_range_decode_v1(amduat_octets_t bytes, + amduat_asl_log_range_t *out_range) { + size_t offset = 0u; + uint32_t version = 0u; + uint32_t refs_len = 0u; + + if (out_range == NULL) { + return false; + } + out_range->start_offset = 0u; + out_range->next_offset = 0u; + out_range->refs = NULL; + out_range->refs_len = 0u; + + if (bytes.len < + AMDUAT_ASL_LOG_RANGE_MAGIC_LEN + 4u + 8u + 8u + 4u || + bytes.data == NULL) { + return false; + } + if (memcmp(bytes.data, k_amduat_asl_log_range_magic, + AMDUAT_ASL_LOG_RANGE_MAGIC_LEN) != 0) { + return false; + } + offset += AMDUAT_ASL_LOG_RANGE_MAGIC_LEN; + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, &offset, &version) || + version != AMDUAT_ASL_LOG_RANGE_VERSION) { + return false; + } + if (!amduat_asl_read_u64_le(bytes.data, bytes.len, &offset, + &out_range->start_offset) || + !amduat_asl_read_u64_le(bytes.data, bytes.len, &offset, + &out_range->next_offset)) { + return false; + } + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, &offset, &refs_len)) { + return false; + } + if (!amduat_asl_decode_refs(bytes, &offset, refs_len, + &out_range->refs, &out_range->refs_len)) { + return false; + } + return offset == bytes.len; +} + +void amduat_asl_log_range_free(amduat_asl_log_range_t *range) { + if (range == NULL || range->refs == NULL) { + return; + } + for (size_t i = 0u; i < range->refs_len; ++i) { + amduat_reference_free(&range->refs[i]); + } + free(range->refs); + range->refs = NULL; + range->refs_len = 0u; +} + +bool amduat_asl_collection_view_encode_v1( + const amduat_asl_collection_view_t *view, + amduat_octets_t *out_bytes) { + uint8_t *buffer; + size_t total_len = 0u; + size_t refs_len_bytes = 0u; + size_t offset = 0u; + + if (out_bytes == NULL || view == NULL) { + return false; + } + out_bytes->data = NULL; + out_bytes->len = 0u; + + if (!amduat_asl_add_size(&total_len, + AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN + 4u + + 8u + 8u + 4u)) { + return false; + } + if (!amduat_asl_encode_refs(view->refs, view->refs_len, &refs_len_bytes)) { + return false; + } + if (!amduat_asl_add_size(&total_len, refs_len_bytes)) { + return false; + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + memcpy(buffer + offset, k_amduat_asl_collection_view_magic, + AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN); + offset += AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN; + amduat_asl_store_u32_le(buffer + offset, + AMDUAT_ASL_COLLECTION_VIEW_VERSION); + offset += 4u; + amduat_asl_store_u64_le(buffer + offset, view->computed_from_offset); + offset += 8u; + amduat_asl_store_u64_le(buffer + offset, view->computed_up_to_offset); + offset += 8u; + amduat_asl_store_u32_le(buffer + offset, (uint32_t)view->refs_len); + offset += 4u; + if (!amduat_asl_write_refs(buffer, total_len, &offset, + view->refs, view->refs_len)) { + free(buffer); + return false; + } + + if (offset != total_len) { + free(buffer); + return false; + } + *out_bytes = amduat_octets(buffer, total_len); + return true; +} + +bool amduat_asl_collection_view_decode_v1( + amduat_octets_t bytes, + amduat_asl_collection_view_t *out_view) { + size_t offset = 0u; + uint32_t version = 0u; + uint32_t refs_len = 0u; + + if (out_view == NULL) { + return false; + } + out_view->computed_from_offset = 0u; + out_view->computed_up_to_offset = 0u; + out_view->refs = NULL; + out_view->refs_len = 0u; + + if (bytes.len < + AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN + 4u + 8u + 8u + 4u || + bytes.data == NULL) { + return false; + } + if (memcmp(bytes.data, k_amduat_asl_collection_view_magic, + AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN) != 0) { + return false; + } + offset += AMDUAT_ASL_COLLECTION_VIEW_MAGIC_LEN; + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, &offset, &version) || + version != AMDUAT_ASL_COLLECTION_VIEW_VERSION) { + return false; + } + if (!amduat_asl_read_u64_le(bytes.data, bytes.len, &offset, + &out_view->computed_from_offset) || + !amduat_asl_read_u64_le(bytes.data, bytes.len, &offset, + &out_view->computed_up_to_offset)) { + return false; + } + if (!amduat_asl_read_u32_le(bytes.data, bytes.len, &offset, &refs_len)) { + return false; + } + if (!amduat_asl_decode_refs(bytes, &offset, refs_len, + &out_view->refs, &out_view->refs_len)) { + return false; + } + return offset == bytes.len; +} + +void amduat_asl_collection_view_free(amduat_asl_collection_view_t *view) { + if (view == NULL || view->refs == NULL) { + return; + } + for (size_t i = 0u; i < view->refs_len; ++i) { + amduat_reference_free(&view->refs[i]); + } + free(view->refs); + view->refs = NULL; + view->refs_len = 0u; +} diff --git a/src/near_core/asl/none.c b/src/near_core/asl/none.c new file mode 100644 index 0000000..92fa9c7 --- /dev/null +++ b/src/near_core/asl/none.c @@ -0,0 +1,110 @@ +#include "amduat/asl/none.h" + +#include +#include +#include + +enum { + AMDUAT_ASL_NONE_MAGIC_LEN = 8, + AMDUAT_ASL_NONE_VERSION = 1 +}; + +static const uint8_t k_amduat_asl_none_magic[AMDUAT_ASL_NONE_MAGIC_LEN] = { + 'A', 'S', 'L', 'N', 'O', 'N', '1', '\0' +}; + +static void amduat_asl_none_store_u32_le(uint8_t *out, uint32_t value) { + out[0] = (uint8_t)(value & 0xffu); + out[1] = (uint8_t)((value >> 8) & 0xffu); + out[2] = (uint8_t)((value >> 16) & 0xffu); + out[3] = (uint8_t)((value >> 24) & 0xffu); +} + +static bool amduat_asl_none_read_u32_le(const uint8_t *data, + size_t len, + size_t *offset, + uint32_t *out) { + if (len - *offset < 4u) { + return false; + } + *out = (uint32_t)data[*offset] | + ((uint32_t)data[*offset + 1u] << 8) | + ((uint32_t)data[*offset + 2u] << 16) | + ((uint32_t)data[*offset + 3u] << 24); + *offset += 4u; + return true; +} + +bool amduat_asl_none_encode_v1(amduat_octets_t *out_bytes) { + uint8_t *buffer; + size_t offset = 0u; + + if (out_bytes == NULL) { + return false; + } + out_bytes->data = NULL; + out_bytes->len = 0u; + + buffer = (uint8_t *)malloc(AMDUAT_ASL_NONE_MAGIC_LEN + 4u); + if (buffer == NULL) { + return false; + } + + memcpy(buffer + offset, k_amduat_asl_none_magic, AMDUAT_ASL_NONE_MAGIC_LEN); + offset += AMDUAT_ASL_NONE_MAGIC_LEN; + amduat_asl_none_store_u32_le(buffer + offset, AMDUAT_ASL_NONE_VERSION); + offset += 4u; + + out_bytes->data = buffer; + out_bytes->len = offset; + return true; +} + +bool amduat_asl_none_decode_v1(amduat_octets_t bytes) { + size_t offset = 0u; + uint32_t version = 0u; + + if (bytes.len != AMDUAT_ASL_NONE_MAGIC_LEN + 4u) { + return false; + } + if (bytes.data == NULL) { + return false; + } + if (memcmp(bytes.data, k_amduat_asl_none_magic, + AMDUAT_ASL_NONE_MAGIC_LEN) != 0) { + return false; + } + offset += AMDUAT_ASL_NONE_MAGIC_LEN; + if (!amduat_asl_none_read_u32_le(bytes.data, bytes.len, &offset, &version)) { + return false; + } + if (version != AMDUAT_ASL_NONE_VERSION) { + return false; + } + return offset == bytes.len; +} + +bool amduat_asl_none_is_artifact(const amduat_artifact_t *artifact) { + if (artifact == NULL) { + return false; + } + if (!artifact->has_type_tag || + artifact->type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_NONE_1) { + return false; + } + return amduat_asl_none_decode_v1(artifact->bytes); +} + +bool amduat_asl_none_artifact(amduat_artifact_t *out_artifact) { + amduat_octets_t bytes = amduat_octets(NULL, 0u); + + if (out_artifact == NULL) { + return false; + } + if (!amduat_asl_none_encode_v1(&bytes)) { + return false; + } + *out_artifact = + amduat_artifact_with_type(bytes, amduat_type_tag(AMDUAT_TYPE_TAG_ASL_NONE_1)); + return true; +} diff --git a/src/near_core/format/pel.c b/src/near_core/format/pel.c index 9115b83..07ea4ab 100644 --- a/src/near_core/format/pel.c +++ b/src/near_core/format/pel.c @@ -95,6 +95,16 @@ const char *amduat_format_pel_kernel_kind_name( return "const"; case AMDUAT_PEL_KERNEL_OP_HASH_ASL1: return "hash_asl1"; + case AMDUAT_PEL_KERNEL_OP_PARAMS: + return "params"; + case AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE: + return "format_encode"; + case AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE: + return "collection_snapshot_decode"; + case AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE: + return "log_read_range"; + case AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS: + return "collection_merge_refs"; default: return "unknown"; } diff --git a/src/pel_stack/opreg/kernel.c b/src/pel_stack/opreg/kernel.c index a8bf906..a7e46cb 100644 --- a/src/pel_stack/opreg/kernel.c +++ b/src/pel_stack/opreg/kernel.c @@ -1,5 +1,6 @@ #include "amduat/pel/opreg_kernel.h" #include "amduat/pel/opreg_kernel_params.h" +#include "kernel_collection.h" #include "amduat/hash/asl1.h" #include @@ -64,8 +65,32 @@ static const amduat_pel_kernel_op_desc_t k_kernel_descs[] = { 3, 1 }, + { + AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE, + AMDUAT_PEL_KERNEL_OP_CODE_COLLECTION_SNAPSHOT_DECODE, + 1, + 1, + 1 + }, + { + AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE, + AMDUAT_PEL_KERNEL_OP_CODE_LOG_READ_RANGE, + 3, + 3, + 1 + }, + { + AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS, + AMDUAT_PEL_KERNEL_OP_CODE_COLLECTION_MERGE_REFS, + 4, + 4, + 1 + }, }; +static amduat_pel_kernel_artifact_resolver_t g_resolver = NULL; +static void *g_resolver_ctx = NULL; + const amduat_pel_kernel_op_desc_t *amduat_pel_kernel_op_lookup( amduat_octets_t name, uint32_t version) { @@ -90,6 +115,16 @@ const amduat_pel_kernel_op_desc_t *amduat_pel_kernel_op_lookup( if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE_NAME)) { return &k_kernel_descs[5]; } + if (amduat_name_eq(name, + AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE_NAME)) { + return &k_kernel_descs[6]; + } + if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE_NAME)) { + return &k_kernel_descs[7]; + } + if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS_NAME)) { + return &k_kernel_descs[8]; + } return NULL; } @@ -115,11 +150,37 @@ const char *amduat_pel_kernel_op_name(amduat_pel_kernel_op_kind_t kind) { return AMDUAT_PEL_KERNEL_OP_PARAMS_NAME; case AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE: return AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE_NAME; + case AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE: + return AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE_NAME; + case AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE: + return AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE_NAME; + case AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS: + return AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS_NAME; default: return NULL; } } +void amduat_pel_kernel_set_artifact_resolver( + amduat_pel_kernel_artifact_resolver_t resolver, + void *ctx) { + g_resolver = resolver; + g_resolver_ctx = ctx; +} + +void amduat_pel_kernel_clear_artifact_resolver(void) { + g_resolver = NULL; + g_resolver_ctx = NULL; +} + +bool amduat_pel_kernel_resolve_artifact(amduat_reference_t ref, + amduat_artifact_t *out_artifact) { + if (g_resolver == NULL) { + return false; + } + return g_resolver(ref, out_artifact, g_resolver_ctx); +} + static bool amduat_type_tags_match(const amduat_artifact_t *a, const amduat_artifact_t *b) { if (a->has_type_tag != b->has_type_tag) { @@ -1537,6 +1598,15 @@ bool amduat_pel_kernel_op_eval( case AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE: return amduat_kernel_format_encode(inputs, inputs_len, out_outputs, out_outputs_len, out_status_code); + case AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE: + return amduat_kernel_collection_snapshot_decode( + inputs, inputs_len, out_outputs, out_outputs_len, out_status_code); + case AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE: + return amduat_kernel_log_read_range( + inputs, inputs_len, out_outputs, out_outputs_len, out_status_code); + case AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS: + return amduat_kernel_collection_merge_refs( + inputs, inputs_len, out_outputs, out_outputs_len, out_status_code); default: *out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL; return false; diff --git a/src/pel_stack/opreg/kernel_collection.c b/src/pel_stack/opreg/kernel_collection.c new file mode 100644 index 0000000..453ae6d --- /dev/null +++ b/src/pel_stack/opreg/kernel_collection.c @@ -0,0 +1,615 @@ +#include "kernel_collection.h" + +#include "amduat/asl/collection.h" +#include "amduat/asl/collection_view.h" +#include "amduat/asl/log_store.h" +#include "amduat/asl/none.h" +#include "amduat/asl/record.h" + +#include +#include +#include + +static bool amduat_alloc_outputs(size_t count, + amduat_artifact_t **out_outputs) { + amduat_artifact_t *outputs; + + if (out_outputs == NULL) { + return false; + } + outputs = (amduat_artifact_t *)calloc(count, sizeof(*outputs)); + if (outputs == NULL) { + return false; + } + *out_outputs = outputs; + return true; +} + +static bool amduat_load_u64_le(amduat_octets_t bytes, + size_t offset, + uint64_t *out) { + const uint8_t *data; + + if (out == NULL) { + return false; + } + if (bytes.len - offset < 8u || bytes.data == NULL) { + return false; + } + data = bytes.data + offset; + *out = (uint64_t)data[0] | + ((uint64_t)data[1] << 8) | + ((uint64_t)data[2] << 16) | + ((uint64_t)data[3] << 24) | + ((uint64_t)data[4] << 32) | + ((uint64_t)data[5] << 40) | + ((uint64_t)data[6] << 48) | + ((uint64_t)data[7] << 56); + return true; +} + +static bool amduat_load_u32_le(amduat_octets_t bytes, + size_t offset, + uint32_t *out) { + const uint8_t *data; + + if (out == NULL) { + return false; + } + if (bytes.len - offset < 4u || bytes.data == NULL) { + return false; + } + data = bytes.data + offset; + *out = (uint32_t)data[0] | + ((uint32_t)data[1] << 8) | + ((uint32_t)data[2] << 16) | + ((uint32_t)data[3] << 24); + return true; +} + +static bool amduat_decode_params(const amduat_artifact_t *artifact, + uint64_t *out_from, + uint32_t *out_limit) { + const char k_params_schema[] = "pel/params"; + amduat_asl_record_t record; + bool ok = false; + + if (artifact == NULL || out_from == NULL || out_limit == NULL) { + return false; + } + if (!artifact->has_type_tag || + artifact->type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_RECORD_1) { + return false; + } + if (!amduat_asl_record_decode_v1(artifact->bytes, &record)) { + return false; + } + if (record.schema.len != strlen(k_params_schema) || + record.schema.data == NULL || + memcmp(record.schema.data, k_params_schema, + record.schema.len) != 0) { + amduat_asl_record_free(&record); + return false; + } + if (record.payload.len != 12u) { + amduat_asl_record_free(&record); + return false; + } + if (!amduat_load_u64_le(record.payload, 0u, out_from) || + !amduat_load_u32_le(record.payload, 8u, out_limit)) { + amduat_asl_record_free(&record); + return false; + } + ok = true; + amduat_asl_record_free(&record); + return ok; +} + +static bool amduat_log_chunk_from_artifact( + const amduat_artifact_t *artifact, + amduat_asl_log_chunk_t *out_chunk) { + if (artifact == NULL || out_chunk == NULL) { + return false; + } + if (!artifact->has_type_tag || + artifact->type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_LOG_CHUNK_1) { + return false; + } + return amduat_asl_log_chunk_decode_v1(artifact->bytes, out_chunk) == + AMDUAT_ASL_STORE_OK; +} + +bool amduat_kernel_collection_snapshot_decode( + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + uint32_t *out_status_code) { + amduat_asl_collection_snapshot_payload_t snapshot; + amduat_asl_collection_snapshot_info_t info; + amduat_asl_record_t record; + amduat_octets_t encoded = amduat_octets(NULL, 0u); + bool ok = false; + + if (inputs == NULL || inputs_len != 1u) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL; + } + return false; + } + + memset(&snapshot, 0, sizeof(snapshot)); + memset(&info, 0, sizeof(info)); + memset(&record, 0, sizeof(record)); + + if (amduat_asl_none_is_artifact(&inputs[0])) { + info.snapshot_at_offset = 0u; + info.refs = NULL; + info.refs_len = 0u; + } else { + if (!inputs[0].has_type_tag || + inputs[0].type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_RECORD_1) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_COLLECTION_SNAPSHOT_INVALID; + } + return false; + } + if (!amduat_asl_record_decode_v1(inputs[0].bytes, &record)) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_COLLECTION_SNAPSHOT_INVALID; + } + return false; + } + if (record.schema.len != strlen("collection/snapshot") || + record.schema.data == NULL || + memcmp(record.schema.data, "collection/snapshot", + record.schema.len) != 0) { + amduat_asl_record_free(&record); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_COLLECTION_SNAPSHOT_INVALID; + } + return false; + } + if (!amduat_asl_collection_snapshot_payload_decode_v1(record.payload, + &snapshot)) { + amduat_asl_record_free(&record); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_COLLECTION_SNAPSHOT_INVALID; + } + return false; + } + info.snapshot_at_offset = snapshot.snapshot_offset; + info.refs = snapshot.refs; + info.refs_len = snapshot.refs_len; + amduat_asl_record_free(&record); + } + + if (!amduat_asl_collection_snapshot_info_encode_v1(&info, &encoded)) { + amduat_asl_collection_snapshot_payload_free(&snapshot); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + + if (!amduat_alloc_outputs(1u, out_outputs)) { + amduat_asl_collection_snapshot_payload_free(&snapshot); + free((void *)encoded.data); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + + (*out_outputs)[0] = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_TYPE_TAG_ASL_SNAPSHOT_INFO_1)); + if (out_outputs_len != NULL) { + *out_outputs_len = 1u; + } + ok = true; + + amduat_asl_collection_snapshot_payload_free(&snapshot); + return ok; +} + +bool amduat_kernel_log_read_range( + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + uint32_t *out_status_code) { + amduat_asl_log_range_t range; + amduat_octets_t encoded = amduat_octets(NULL, 0u); + uint64_t from_offset = 0u; + uint32_t limit = 0u; + uint64_t limit_from_offset = 0u; + uint32_t limit_value = 0u; + bool ok = false; + + if (inputs == NULL || inputs_len != 3u) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL; + } + return false; + } + + if (!amduat_decode_params(&inputs[1], &from_offset, &limit_value)) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_PARAMS_INVALID; + } + return false; + } + if (!amduat_decode_params(&inputs[2], &limit_from_offset, &limit)) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_PARAMS_INVALID; + } + return false; + } + (void)limit_from_offset; + (void)limit_value; + + memset(&range, 0, sizeof(range)); + range.start_offset = from_offset; + range.next_offset = from_offset; + range.refs = NULL; + range.refs_len = 0u; + + if (limit == 0u || amduat_asl_none_is_artifact(&inputs[0])) { + goto encode_range; + } + + { + amduat_asl_log_chunk_t *chunks = NULL; + size_t chunks_len = 0u; + amduat_asl_log_chunk_t head_chunk; + uint64_t head_end_offset = 0u; + if (!amduat_log_chunk_from_artifact(&inputs[0], &head_chunk)) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_LOG_CHUNK_INVALID; + } + return false; + } + if (head_chunk.base_offset > + UINT64_MAX - (uint64_t)head_chunk.entry_count) { + amduat_asl_log_chunk_free(&head_chunk); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_LOG_CHUNK_INVALID; + } + return false; + } + head_end_offset = head_chunk.base_offset + head_chunk.entry_count; + + { + amduat_asl_log_chunk_t *next = + (amduat_asl_log_chunk_t *)realloc( + chunks, (chunks_len + 1u) * sizeof(*chunks)); + if (next == NULL) { + amduat_asl_log_chunk_free(&head_chunk); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + chunks = next; + chunks[chunks_len++] = head_chunk; + } + + if (from_offset >= head_end_offset) { + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + range.next_offset = from_offset; + goto encode_range; + } + + while (true) { + amduat_asl_log_chunk_t chunk; + amduat_artifact_t prev_artifact; + + if (chunks[chunks_len - 1u].base_offset <= from_offset || + !chunks[chunks_len - 1u].has_prev) { + break; + } + + memset(&prev_artifact, 0, sizeof(prev_artifact)); + if (!amduat_pel_kernel_resolve_artifact( + chunks[chunks_len - 1u].prev_ref, &prev_artifact)) { + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_REF_RESOLVE_FAILED; + } + return false; + } + if (!amduat_log_chunk_from_artifact(&prev_artifact, &chunk)) { + amduat_artifact_free(&prev_artifact); + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_LOG_CHUNK_INVALID; + } + return false; + } + amduat_artifact_free(&prev_artifact); + + { + amduat_asl_log_chunk_t *next = + (amduat_asl_log_chunk_t *)realloc( + chunks, (chunks_len + 1u) * sizeof(*chunks)); + if (next == NULL) { + amduat_asl_log_chunk_free(&chunk); + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + chunks = next; + chunks[chunks_len++] = chunk; + } + } + + if (limit > SIZE_MAX) { + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_LOG_RANGE_INVALID; + } + return false; + } + if (limit != 0u) { + range.refs = (amduat_reference_t *)calloc(limit, sizeof(*range.refs)); + if (range.refs == NULL) { + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + } + + for (size_t i = 0u; i < chunks_len / 2u; ++i) { + amduat_asl_log_chunk_t tmp = chunks[i]; + chunks[i] = chunks[chunks_len - 1u - i]; + chunks[chunks_len - 1u - i] = tmp; + } + + range.refs_len = 0u; + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_t *chunk = &chunks[i]; + for (uint32_t j = 0u; j < chunk->entry_count; ++j) { + uint64_t offset = chunk->base_offset + j; + if (offset < from_offset) { + continue; + } + if (range.refs_len == limit) { + goto done_collect; + } + if (!amduat_reference_clone(chunk->entries[j].payload_ref, + &range.refs[range.refs_len])) { + for (size_t k = 0u; k < chunks_len; ++k) { + amduat_asl_log_chunk_free(&chunks[k]); + } + free(chunks); + amduat_asl_log_range_free(&range); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + range.refs_len++; + range.next_offset = offset + 1u; + } + } + +done_collect: + if (range.refs_len < limit) { + range.next_offset = head_end_offset; + } + + for (size_t i = 0u; i < chunks_len; ++i) { + amduat_asl_log_chunk_free(&chunks[i]); + } + free(chunks); + } + +encode_range: + if (!amduat_asl_log_range_encode_v1(&range, &encoded)) { + amduat_asl_log_range_free(&range); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + + if (!amduat_alloc_outputs(1u, out_outputs)) { + amduat_asl_log_range_free(&range); + free((void *)encoded.data); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + + (*out_outputs)[0] = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_TYPE_TAG_ASL_LOG_RANGE_1)); + if (out_outputs_len != NULL) { + *out_outputs_len = 1u; + } + ok = true; + amduat_asl_log_range_free(&range); + return ok; +} + +bool amduat_kernel_collection_merge_refs( + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + uint32_t *out_status_code) { + amduat_asl_collection_snapshot_info_t snapshot; + amduat_asl_log_range_t log_range; + amduat_asl_collection_view_t view; + amduat_octets_t encoded = amduat_octets(NULL, 0u); + uint64_t from_offset = 0u; + uint32_t limit = 0u; + uint64_t limit_from_offset = 0u; + uint32_t limit_value = 0u; + size_t total_refs = 0u; + size_t start_index = 0u; + size_t end_index = 0u; + bool ok = false; + + if (inputs == NULL || inputs_len != 4u) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL; + } + return false; + } + + if (!amduat_decode_params(&inputs[2], &from_offset, &limit_value) || + !amduat_decode_params(&inputs[3], &limit_from_offset, &limit)) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_PARAMS_INVALID; + } + return false; + } + (void)limit_from_offset; + (void)limit_value; + + memset(&snapshot, 0, sizeof(snapshot)); + memset(&log_range, 0, sizeof(log_range)); + memset(&view, 0, sizeof(view)); + + if (!inputs[0].has_type_tag || + inputs[0].type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_SNAPSHOT_INFO_1 || + !amduat_asl_collection_snapshot_info_decode_v1(inputs[0].bytes, + &snapshot)) { + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_COLLECTION_SNAPSHOT_INVALID; + } + return false; + } + if (!inputs[1].has_type_tag || + inputs[1].type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_LOG_RANGE_1 || + !amduat_asl_log_range_decode_v1(inputs[1].bytes, &log_range)) { + amduat_asl_collection_snapshot_info_free(&snapshot); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_LOG_RANGE_INVALID; + } + return false; + } + + if (snapshot.refs_len > SIZE_MAX - log_range.refs_len) { + amduat_asl_collection_snapshot_info_free(&snapshot); + amduat_asl_log_range_free(&log_range); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_COLLECTION_VIEW_INVALID; + } + return false; + } + total_refs = snapshot.refs_len + log_range.refs_len; + if (from_offset > SIZE_MAX) { + start_index = total_refs; + } else { + start_index = (size_t)from_offset; + if (start_index > total_refs) { + start_index = total_refs; + } + } + + if (limit > SIZE_MAX || start_index > SIZE_MAX - (size_t)limit) { + end_index = total_refs; + } else { + end_index = start_index + (size_t)limit; + if (end_index > total_refs) { + end_index = total_refs; + } + } + + view.refs_len = end_index - start_index; + view.refs = NULL; + if (view.refs_len != 0u) { + view.refs = (amduat_reference_t *)calloc(view.refs_len, sizeof(*view.refs)); + if (view.refs == NULL) { + amduat_asl_collection_snapshot_info_free(&snapshot); + amduat_asl_log_range_free(&log_range); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + } + + for (size_t i = 0u; i < view.refs_len; ++i) { + size_t idx = start_index + i; + const amduat_reference_t *src = + (idx < snapshot.refs_len) + ? &snapshot.refs[idx] + : &log_range.refs[idx - snapshot.refs_len]; + if (!amduat_reference_clone(*src, &view.refs[i])) { + amduat_asl_collection_view_free(&view); + amduat_asl_collection_snapshot_info_free(&snapshot); + amduat_asl_log_range_free(&log_range); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + } + + view.computed_from_offset = from_offset; + if (log_range.refs_len < limit) { + view.computed_up_to_offset = log_range.next_offset; + } else if (from_offset > UINT64_MAX - (uint64_t)view.refs_len) { + view.computed_up_to_offset = UINT64_MAX; + } else { + view.computed_up_to_offset = from_offset + (uint64_t)view.refs_len; + } + + if (!amduat_asl_collection_view_encode_v1(&view, &encoded)) { + amduat_asl_collection_view_free(&view); + amduat_asl_collection_snapshot_info_free(&snapshot); + amduat_asl_log_range_free(&log_range); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + + if (!amduat_alloc_outputs(1u, out_outputs)) { + amduat_asl_collection_view_free(&view); + amduat_asl_collection_snapshot_info_free(&snapshot); + amduat_asl_log_range_free(&log_range); + free((void *)encoded.data); + if (out_status_code) { + *out_status_code = AMDUAT_PEL_KERNEL_STATUS_OOM; + } + return false; + } + + (*out_outputs)[0] = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_TYPE_TAG_ASL_COLLECTION_VIEW_1)); + if (out_outputs_len != NULL) { + *out_outputs_len = 1u; + } + ok = true; + + amduat_asl_collection_view_free(&view); + amduat_asl_collection_snapshot_info_free(&snapshot); + amduat_asl_log_range_free(&log_range); + return ok; +} diff --git a/src/pel_stack/opreg/kernel_collection.h b/src/pel_stack/opreg/kernel_collection.h new file mode 100644 index 0000000..d1d4c30 --- /dev/null +++ b/src/pel_stack/opreg/kernel_collection.h @@ -0,0 +1,29 @@ +#ifndef AMDUAT_PEL_OPREG_KERNEL_COLLECTION_H +#define AMDUAT_PEL_OPREG_KERNEL_COLLECTION_H + +#include "amduat/pel/opreg_kernel.h" + +#include + +bool amduat_kernel_collection_snapshot_decode( + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + uint32_t *out_status_code); + +bool amduat_kernel_log_read_range( + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + uint32_t *out_status_code); + +bool amduat_kernel_collection_merge_refs( + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + uint32_t *out_status_code); + +#endif /* AMDUAT_PEL_OPREG_KERNEL_COLLECTION_H */ diff --git a/src/pel_stack/opreg/kernel_params.c b/src/pel_stack/opreg/kernel_params.c index 7617b97..84e8103 100644 --- a/src/pel_stack/opreg/kernel_params.c +++ b/src/pel_stack/opreg/kernel_params.c @@ -133,6 +133,12 @@ bool amduat_pel_kernel_params_decode( return amduat_decode_unit(params_bytes); case AMDUAT_PEL_KERNEL_OP_FORMAT_ENCODE: return amduat_decode_unit(params_bytes); + case AMDUAT_PEL_KERNEL_OP_COLLECTION_SNAPSHOT_DECODE: + return amduat_decode_unit(params_bytes); + case AMDUAT_PEL_KERNEL_OP_LOG_READ_RANGE: + return amduat_decode_unit(params_bytes); + case AMDUAT_PEL_KERNEL_OP_COLLECTION_MERGE_REFS: + return amduat_decode_unit(params_bytes); default: return false; } diff --git a/src/pel_stack/surf/surf.c b/src/pel_stack/surf/surf.c index 3f3fb54..3289852 100644 --- a/src/pel_stack/surf/surf.c +++ b/src/pel_stack/surf/surf.c @@ -6,6 +6,7 @@ #include "amduat/enc/pel_program_dag.h" #include "amduat/enc/pel_trace_dag.h" #include "amduat/pel/derivation_sid.h" +#include "amduat/pel/opreg_kernel.h" #include "amduat/util/log.h" #include "pel_program_dag_internal.h" #include "amduat/pel/program_dag_desc.h" @@ -35,6 +36,17 @@ void amduat_pel_surf_free_ref(amduat_reference_t *ref) { amduat_reference_free(ref); } +static bool amduat_pel_surf_resolve_artifact(amduat_reference_t ref, + amduat_artifact_t *out_artifact, + void *ctx) { + amduat_asl_store_t *store = (amduat_asl_store_t *)ctx; + if (store == NULL || out_artifact == NULL) { + return false; + } + return amduat_asl_store_get(store, ref, out_artifact) == + AMDUAT_ASL_STORE_OK; +} + static void amduat_init_core_result(amduat_pel_execution_result_value_t *result, amduat_reference_t scheme_ref, amduat_pel_execution_status_t status, @@ -691,9 +703,12 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, program_decoded = true; const amduat_artifact_t *params_arg = has_params_artifact ? ¶ms_artifact : NULL; + amduat_pel_kernel_set_artifact_resolver( + amduat_pel_surf_resolve_artifact, store); if (!amduat_pel_program_dag_exec_trace( &program, input_artifacts, input_refs_len, params_arg, &outputs, &outputs_len, &core_result, &trace_eval)) { + amduat_pel_kernel_clear_artifact_resolver(); amduat_artifact_free(&program_artifact); amduat_enc_pel_program_dag_free(&program); for (i = 0; i < input_refs_len; ++i) { @@ -706,6 +721,7 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, amduat_pel_program_dag_free_outputs(outputs, outputs_len); return false; } + amduat_pel_kernel_clear_artifact_resolver(); executed = true; } } diff --git a/src/tools/amduat_pel_cli.c b/src/tools/amduat_pel_cli.c index 679c1be..055caf0 100644 --- a/src/tools/amduat_pel_cli.c +++ b/src/tools/amduat_pel_cli.c @@ -4,6 +4,8 @@ #include "amduat/asl/asl_pointer_fs.h" #include "amduat/asl/log_store.h" #include "amduat/asl/collection.h" +#include "amduat/asl/collection_view.h" +#include "amduat/asl/none.h" #include "amduat/asl/record.h" #include "amduat/asl/asl_store_fs.h" #include "amduat/asl/asl_store_fs_meta.h" @@ -74,6 +76,8 @@ static void amduat_pel_cli_print_usage(FILE *stream) { " result Surface result tools (decode).\n" " op Kernel op registry tools.\n" " log Append-only log tools (append, read).\n" + " col Collection tools (append, snapshot, read, view).\n" + " rec ASL record tools (put, get).\n" " matcache Materialization cache tools (get, sid).\n" " ptr Named pointer tools (get, cas).\n" " scheme Scheme refs, type tags, profile IDs.\n" @@ -145,6 +149,14 @@ static void amduat_pel_cli_print_usage(FILE *stream) { " amduat-pel log append --log NAME --kind N --ref REF [--actor TEXT]\n" " amduat-pel log read --log NAME --from OFFSET --limit N\n" "\n" + "col:\n" + " amduat-pel col append --name NAME --record-ref REF [--kind N]\n" + " [--actor TEXT]\n" + " amduat-pel col snapshot --name NAME [--up-to OFFSET]\n" + " amduat-pel col read --name NAME --from OFFSET --limit N\n" + " amduat-pel col view --name NAME --from OFFSET --limit N\n" + " [--dump-program-ref]\n" + "\n" "scheme:\n" " amduat-pel scheme show [--format text|json] [--ref-format hex|bytes]\n" " amduat-pel scheme dag-ref [--format hex|bytes]\n" @@ -173,7 +185,8 @@ static void amduat_pel_cli_print_usage(FILE *stream) { " - Only PEL/PROGRAM-DAG/1 is supported; other scheme refs yield SCHEME_UNSUPPORTED.\n" " - Expected type tags: program 0x00000101, trace 0x00000102, result 0x00000103.\n" " - Encoding profile IDs: program 0x0101, trace 0x0102, result 0x0103.\n" - " - Kernel ops: pel.bytes.concat, pel.bytes.slice, pel.bytes.const, pel.bytes.hash.asl1, pel.bytes.params, pel.format.encode.\n" + " - Kernel ops: pel.bytes.concat, pel.bytes.slice, pel.bytes.const, pel.bytes.hash.asl1, pel.bytes.params, pel.format.encode,\n" + " collection.snapshot_decode_v1, log.read_range_v1, collection.merge_refs_v1.\n" " - --ref-format bytes expects REF arguments to be a path or '-' (raw reference bytes).\n" " - --inputs-file with --ref-format bytes expects raw concatenated references.\n" " - run stores derivation records for outputs; use --no-index to skip.\n"); @@ -3230,6 +3243,232 @@ static bool amduat_pel_cli_init_store(const char *root, return true; } +static bool amduat_pel_cli_build_collection_head_name(const char *name, + char **out_name) { + size_t name_len; + size_t total_len; + char *buffer; + size_t offset = 0u; + + if (name == NULL || out_name == NULL) { + return false; + } + if (!amduat_asl_pointer_name_is_valid(name)) { + return false; + } + name_len = strlen(name); + total_len = 11u + name_len + 5u + 1u; + buffer = (char *)malloc(total_len); + if (buffer == NULL) { + return false; + } + memcpy(buffer + offset, "collection/", 11u); + offset += 11u; + memcpy(buffer + offset, name, name_len); + offset += name_len; + memcpy(buffer + offset, "/head", 5u); + offset += 5u; + buffer[offset] = '\0'; + *out_name = buffer; + return true; +} + +static bool amduat_pel_cli_build_collection_log_head_name(const char *name, + char **out_name) { + size_t name_len; + size_t log_name_len; + size_t total_len; + char *buffer; + size_t offset = 0u; + + if (name == NULL || out_name == NULL) { + return false; + } + if (!amduat_asl_pointer_name_is_valid(name)) { + return false; + } + name_len = strlen(name); + log_name_len = 11u + name_len + 4u; + total_len = 4u + log_name_len + 5u + 1u; + buffer = (char *)malloc(total_len); + if (buffer == NULL) { + return false; + } + memcpy(buffer + offset, "log/", 4u); + offset += 4u; + memcpy(buffer + offset, "collection/", 11u); + offset += 11u; + memcpy(buffer + offset, name, name_len); + offset += name_len; + memcpy(buffer + offset, "/log", 4u); + offset += 4u; + memcpy(buffer + offset, "/head", 5u); + offset += 5u; + buffer[offset] = '\0'; + *out_name = buffer; + return true; +} + +static bool amduat_pel_cli_get_none_ref(amduat_asl_store_t *store, + amduat_reference_t *out_ref) { + amduat_artifact_t none_artifact; + + if (store == NULL || out_ref == NULL) { + return false; + } + if (!amduat_asl_none_artifact(&none_artifact)) { + return false; + } + if (amduat_asl_store_put(store, none_artifact, out_ref) != + AMDUAT_ASL_STORE_OK) { + amduat_artifact_free(&none_artifact); + return false; + } + amduat_artifact_free(&none_artifact); + return true; +} + +static bool amduat_pel_cli_put_view_params(amduat_asl_store_t *store, + uint64_t from_offset, + uint32_t limit, + amduat_reference_t *out_ref) { + uint8_t payload[12]; + amduat_asl_record_t record; + + if (store == NULL || out_ref == NULL) { + return false; + } + payload[0] = (uint8_t)(from_offset & 0xffu); + payload[1] = (uint8_t)((from_offset >> 8) & 0xffu); + payload[2] = (uint8_t)((from_offset >> 16) & 0xffu); + payload[3] = (uint8_t)((from_offset >> 24) & 0xffu); + payload[4] = (uint8_t)((from_offset >> 32) & 0xffu); + payload[5] = (uint8_t)((from_offset >> 40) & 0xffu); + payload[6] = (uint8_t)((from_offset >> 48) & 0xffu); + payload[7] = (uint8_t)((from_offset >> 56) & 0xffu); + payload[8] = (uint8_t)(limit & 0xffu); + payload[9] = (uint8_t)((limit >> 8) & 0xffu); + payload[10] = (uint8_t)((limit >> 16) & 0xffu); + payload[11] = (uint8_t)((limit >> 24) & 0xffu); + + record.schema = amduat_octets("pel/params", strlen("pel/params")); + record.payload = amduat_octets(payload, sizeof(payload)); + + if (amduat_asl_record_store_put(store, + record.schema, + record.payload, + out_ref) != AMDUAT_ASL_STORE_OK) { + return false; + } + return true; +} + +static void amduat_pel_cli_program_free(amduat_pel_program_t *program) { + if (program == NULL || program->nodes == NULL) { + return; + } + for (size_t i = 0u; i < program->nodes_len; ++i) { + free(program->nodes[i].inputs); + } + free(program->nodes); + free(program->roots); + program->nodes = NULL; + program->roots = NULL; + program->nodes_len = 0u; + program->roots_len = 0u; +} + +static bool amduat_pel_cli_build_collection_view_program( + amduat_pel_program_t *out_program) { + static const char k_op_snapshot[] = "collection.snapshot_decode_v1"; + static const char k_op_read_range[] = "log.read_range_v1"; + static const char k_op_merge[] = "collection.merge_refs_v1"; + amduat_pel_node_t *nodes; + amduat_pel_root_ref_t *roots; + + if (out_program == NULL) { + return false; + } + memset(out_program, 0, sizeof(*out_program)); + + nodes = (amduat_pel_node_t *)calloc(3u, sizeof(*nodes)); + roots = (amduat_pel_root_ref_t *)calloc(1u, sizeof(*roots)); + if (nodes == NULL || roots == NULL) { + free(nodes); + free(roots); + return false; + } + + nodes[0].id = 1u; + nodes[0].op.name = amduat_octets(k_op_snapshot, strlen(k_op_snapshot)); + nodes[0].op.version = 1u; + nodes[0].inputs_len = 1u; + nodes[0].inputs = + (amduat_pel_dag_input_t *)calloc(1u, sizeof(*nodes[0].inputs)); + if (nodes[0].inputs == NULL) { + free(nodes); + free(roots); + return false; + } + nodes[0].inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + nodes[0].inputs[0].value.external.input_index = 0u; + nodes[0].params = amduat_octets(NULL, 0u); + + nodes[1].id = 2u; + nodes[1].op.name = amduat_octets(k_op_read_range, strlen(k_op_read_range)); + nodes[1].op.version = 1u; + nodes[1].inputs_len = 3u; + nodes[1].inputs = + (amduat_pel_dag_input_t *)calloc(3u, sizeof(*nodes[1].inputs)); + if (nodes[1].inputs == NULL) { + free(nodes[0].inputs); + free(nodes); + free(roots); + return false; + } + nodes[1].inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + nodes[1].inputs[0].value.external.input_index = 1u; + nodes[1].inputs[1].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + nodes[1].inputs[1].value.external.input_index = 2u; + nodes[1].inputs[2].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + nodes[1].inputs[2].value.external.input_index = 3u; + nodes[1].params = amduat_octets(NULL, 0u); + + nodes[2].id = 3u; + nodes[2].op.name = amduat_octets(k_op_merge, strlen(k_op_merge)); + nodes[2].op.version = 1u; + nodes[2].inputs_len = 4u; + nodes[2].inputs = + (amduat_pel_dag_input_t *)calloc(4u, sizeof(*nodes[2].inputs)); + if (nodes[2].inputs == NULL) { + free(nodes[1].inputs); + free(nodes[0].inputs); + free(nodes); + free(roots); + return false; + } + nodes[2].inputs[0].kind = AMDUAT_PEL_DAG_INPUT_NODE; + nodes[2].inputs[0].value.node.node_id = 1u; + nodes[2].inputs[0].value.node.output_index = 0u; + nodes[2].inputs[1].kind = AMDUAT_PEL_DAG_INPUT_NODE; + nodes[2].inputs[1].value.node.node_id = 2u; + nodes[2].inputs[1].value.node.output_index = 0u; + nodes[2].inputs[2].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + nodes[2].inputs[2].value.external.input_index = 2u; + nodes[2].inputs[3].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + nodes[2].inputs[3].value.external.input_index = 3u; + nodes[2].params = amduat_octets(NULL, 0u); + + roots[0].node_id = 3u; + roots[0].output_index = 0u; + + out_program->nodes = nodes; + out_program->nodes_len = 3u; + out_program->roots = roots; + out_program->roots_len = 1u; + return true; +} + static int amduat_pel_cli_cmd_log_append( int argc, char **argv, @@ -3895,6 +4134,283 @@ static int amduat_pel_cli_cmd_col_read( return AMDUAT_PEL_CLI_EXIT_OK; } +static int amduat_pel_cli_cmd_col_view( + int argc, + char **argv, + const amduat_pel_cli_global_opts_t *global) { + const char *name = NULL; + uint64_t from = 0u; + unsigned long long limit = 0u; + bool dump_program_ref = false; + amduat_asl_store_t store; + amduat_asl_store_fs_t fs; + amduat_asl_pointer_store_t pointer_store; + amduat_reference_t snapshot_ref; + amduat_reference_t log_head_ref; + amduat_reference_t none_ref; + amduat_reference_t params_ref; + amduat_reference_t program_ref; + amduat_reference_t input_refs[4]; + amduat_pel_program_t program; + amduat_octets_t program_bytes = amduat_octets(NULL, 0u); + amduat_pel_run_result_t run_result; + amduat_artifact_t view_artifact; + amduat_asl_collection_view_t view; + amduat_type_tag_t expected_type_tag; + amduat_asl_encoding_profile_id_t expected_profile; + char *snapshot_name = NULL; + char *log_head_name = NULL; + bool snapshot_exists = false; + bool log_head_exists = false; + bool stdin_used = false; + int exit_code = AMDUAT_PEL_CLI_EXIT_OK; + int i; + + if (global == NULL) { + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + memset(&snapshot_ref, 0, sizeof(snapshot_ref)); + memset(&log_head_ref, 0, sizeof(log_head_ref)); + memset(&none_ref, 0, sizeof(none_ref)); + memset(¶ms_ref, 0, sizeof(params_ref)); + memset(&program_ref, 0, sizeof(program_ref)); + + for (i = 0; i < argc; ++i) { + if (strcmp(argv[i], "--name") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "error: --name requires a value\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + name = argv[++i]; + } else if (strcmp(argv[i], "--from") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "error: --from requires a value\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + from = (uint64_t)strtoull(argv[++i], NULL, 10); + } else if (strcmp(argv[i], "--limit") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "error: --limit requires a value\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + limit = strtoull(argv[++i], NULL, 10); + } else if (strcmp(argv[i], "--dump-program-ref") == 0) { + dump_program_ref = true; + } else if (strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "-h") == 0) { + amduat_pel_cli_print_usage(stdout); + return AMDUAT_PEL_CLI_EXIT_OK; + } else { + fprintf(stderr, "error: unknown option: %s\n", argv[i]); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + } + + if (name == NULL || limit == 0u) { + fprintf(stderr, "error: --name and --limit are required\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + if (limit > UINT32_MAX) { + fprintf(stderr, "error: --limit out of range\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + + if (!amduat_pel_cli_init_store(global->root, &store, &fs)) { + fprintf(stderr, "error: failed to initialize store\n"); + return AMDUAT_PEL_CLI_EXIT_CONFIG; + } + if (!amduat_asl_pointer_store_init(&pointer_store, global->root)) { + fprintf(stderr, "error: failed to init pointer store\n"); + return AMDUAT_PEL_CLI_EXIT_CONFIG; + } + + if (!amduat_pel_cli_get_none_ref(&store, &none_ref)) { + fprintf(stderr, "error: failed to create none artifact\n"); + return AMDUAT_PEL_CLI_EXIT_STORE; + } + if (!amduat_pel_cli_build_collection_head_name(name, &snapshot_name) || + !amduat_pel_cli_build_collection_log_head_name(name, &log_head_name)) { + fprintf(stderr, "error: invalid collection name\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_USAGE; + goto view_cleanup; + } + + if (amduat_asl_pointer_get(&pointer_store, snapshot_name, + &snapshot_exists, &snapshot_ref) != + AMDUAT_ASL_POINTER_OK) { + fprintf(stderr, "error: failed to read collection head\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_IO; + goto view_cleanup; + } + if (!snapshot_exists && + !amduat_reference_clone(none_ref, &snapshot_ref)) { + fprintf(stderr, "error: failed to clone none ref\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + + if (amduat_asl_pointer_get(&pointer_store, log_head_name, + &log_head_exists, &log_head_ref) != + AMDUAT_ASL_POINTER_OK) { + fprintf(stderr, "error: failed to read log head\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_IO; + goto view_cleanup; + } + if (!log_head_exists && + !amduat_reference_clone(none_ref, &log_head_ref)) { + fprintf(stderr, "error: failed to clone none ref\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + + if (!amduat_pel_cli_put_view_params(&store, from, (uint32_t)limit, + ¶ms_ref)) { + fprintf(stderr, "error: failed to store params\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + + if (!amduat_pel_cli_build_collection_view_program(&program)) { + fprintf(stderr, "error: failed to build program\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + + if (!amduat_enc_pel_program_dag_encode_v1(&program, &program_bytes)) { + amduat_pel_cli_program_free(&program); + fprintf(stderr, "error: failed to encode program\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + amduat_pel_cli_program_free(&program); + + if (!amduat_pel_program_dag_desc_get_program_binding(&expected_type_tag, + &expected_profile)) { + fprintf(stderr, "error: failed to load program binding\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + if (expected_profile != AMDUAT_PEL_ENC_PROGRAM_DAG_V1) { + fprintf(stderr, "error: unsupported program profile\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; + goto view_cleanup; + } + + { + amduat_artifact_t program_artifact = + amduat_artifact_with_type(program_bytes, expected_type_tag); + if (amduat_asl_store_put(&store, program_artifact, &program_ref) != + AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "error: failed to store program\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + } + + if (dump_program_ref) { + fputs("program_ref=", stdout); + if (!amduat_format_ref_write_text(stdout, program_ref, + global->ref_format)) { + fprintf(stderr, "error: failed to format program ref\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + fputc('\n', stdout); + } + + input_refs[0] = snapshot_ref; + input_refs[1] = log_head_ref; + input_refs[2] = params_ref; + input_refs[3] = params_ref; + + memset(&run_result, 0, sizeof(run_result)); + if (!amduat_pel_surf_run_with_result(&store, + amduat_pel_program_dag_scheme_ref(), + program_ref, + input_refs, + 4u, + true, + params_ref, + &run_result)) { + fprintf(stderr, "error: PEL surface execution failed\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + + if (!run_result.has_result_value || + run_result.result_value.core_result.status != AMDUAT_PEL_EXEC_STATUS_OK) { + fprintf(stderr, "error: projection execution failed\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + if (run_result.output_refs_len != 1u) { + fprintf(stderr, "error: unexpected output count\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + + memset(&view_artifact, 0, sizeof(view_artifact)); + if (amduat_asl_store_get(&store, run_result.output_refs[0], + &view_artifact) != AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "error: failed to load view artifact\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_STORE; + goto view_cleanup; + } + if (!view_artifact.has_type_tag || + view_artifact.type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_COLLECTION_VIEW_1 || + !amduat_asl_collection_view_decode_v1(view_artifact.bytes, &view)) { + amduat_artifact_free(&view_artifact); + fprintf(stderr, "error: invalid view artifact\n"); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + amduat_artifact_free(&view_artifact); + + fputs("view_ref=", stdout); + if (!amduat_format_ref_write_text(stdout, run_result.output_refs[0], + global->ref_format)) { + fprintf(stderr, "error: failed to format view ref\n"); + amduat_asl_collection_view_free(&view); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + fputc('\n', stdout); + printf("computed_from_offset=%" PRIu64 "\n", view.computed_from_offset); + printf("computed_up_to_offset=%" PRIu64 "\n", view.computed_up_to_offset); + printf("entry_count=%zu\n", view.refs_len); + for (size_t idx = 0u; idx < view.refs_len; ++idx) { + fputs("entry_ref=", stdout); + if (!amduat_format_ref_write_text(stdout, view.refs[idx], + global->ref_format)) { + fprintf(stderr, "error: failed to format entry ref\n"); + amduat_asl_collection_view_free(&view); + exit_code = AMDUAT_PEL_CLI_EXIT_CODEC; + goto view_cleanup; + } + fputc('\n', stdout); + } + amduat_asl_collection_view_free(&view); + +view_cleanup: + if (run_result.has_result_value) { + amduat_enc_pel1_result_free(&run_result.result_value); + } + if (run_result.output_refs != NULL) { + amduat_pel_surf_free_refs(run_result.output_refs, + run_result.output_refs_len); + } + amduat_pel_surf_free_ref(&run_result.result_ref); + amduat_pel_cli_free_reference(&snapshot_ref); + amduat_pel_cli_free_reference(&log_head_ref); + amduat_pel_cli_free_reference(&none_ref); + amduat_pel_cli_free_reference(¶ms_ref); + amduat_pel_cli_free_reference(&program_ref); + free((void *)program_bytes.data); + free(snapshot_name); + free(log_head_name); + return exit_code; +} + static int amduat_pel_cli_cmd_col( int argc, char **argv, @@ -3912,6 +4428,9 @@ static int amduat_pel_cli_cmd_col( if (strcmp(argv[0], "read") == 0) { return amduat_pel_cli_cmd_col_read(argc - 1, argv + 1, global); } + if (strcmp(argv[0], "view") == 0) { + return amduat_pel_cli_cmd_col_view(argc - 1, argv + 1, global); + } fprintf(stderr, "error: unknown col subcommand: %s\n", argv[0]); return AMDUAT_PEL_CLI_EXIT_USAGE; }