Transaction Functions

#include <keychain/keychain_headers.h>

Overview

Transaction functions work with verifiable objects that track the state of application-level consensus processes. A transaction comprises the terms of the consensus process (consensus algorithm, participants, metadata, and initial variables) and a sequence of attestations, each representing a point in time in the consensus process’s state.

Transactions encapsulate functionality common among all verifiable objects (verifiable data, credentials, and transactions), including a list of attestations, tag sets for tags and variables, and serialization methods used during signing and verification.

Object Lifecycle Functions

kc_transaction_construct_from_serialized_data()

int kc_transaction_construct_from_serialized_data(
    kc_transaction_t** out_transaction_ptr,
    const kc_serialized_data_t* serialized_data_ptr
)

Deserializes a transaction from serialized data.

Parameters:

  • out_transaction_ptr - Pointer to transaction pointer (output, caller must free)

  • serialized_data_ptr - Transaction serialized as serialized data

Returns: Error code (0 = success)

Example:

kc_transaction_t* transaction = NULL;
kc_serialized_data_t* serialized_data = NULL;

// ... obtain serialized_data ...

int result = kc_transaction_construct_from_serialized_data(&transaction, serialized_data);
if (result == 0) {
    // Use transaction...
    kc_transaction_destruct(&transaction);
}

kc_transaction_construct_from_serialized_string()

int kc_transaction_construct_from_serialized_string(
    kc_transaction_t** out_transaction_ptr,
    const char* serialized_string,
    const unsigned int serialized_string_size,
    const tkc_serialization_format serialization_format
)

Deserializes a transaction from a string representation.

Parameters:

  • out_transaction_ptr - Pointer to transaction pointer (output, caller must free)

  • serialized_string - Transaction serialized as a string

  • serialized_string_size - Number of bytes in the serialized string

  • serialization_format - Expected serialization format (JSON, XML, or PROTOBUF)

Returns: Error code (0 = success)

Example:

kc_transaction_t* transaction = NULL;
const char* serialized = "{\"consensusAlgorithm\":\"RAFT\",\"quorum\":{...}}";
int result = kc_transaction_construct_from_serialized_string(&transaction,
    serialized, strlen(serialized), TKC_SERIALIZATION_FORMAT_JSON);
if (result == 0) {
    // Use transaction...
    kc_transaction_destruct(&transaction);
}

kc_transaction_construct_from_copy()

int kc_transaction_construct_from_copy(
    kc_transaction_t** out_transaction_ptr,
    const kc_transaction_t* rhs_transaction_ptr
)

Creates a deep copy of a transaction object.

Parameters:

  • out_transaction_ptr - Pointer to new transaction pointer (output, caller must free)

  • rhs_transaction_ptr - Transaction object to copy

Returns: Error code (0 = success)

Example:

kc_transaction_t* original_transaction = NULL;
kc_transaction_t* copied_transaction = NULL;

// ... create original_transaction ...

int result = kc_transaction_construct_from_copy(&copied_transaction, original_transaction);
if (result == 0) {
    // Use copied transaction...
    kc_transaction_destruct(&copied_transaction);
}

kc_transaction_destruct()

int kc_transaction_destruct(kc_transaction_t** transaction_ptr)

Destructs a transaction object and frees its resources.

Parameters:

  • transaction_ptr - Pointer to transaction pointer (set to NULL on success)

Returns: Error code (0 = success)

Consensus Configuration Functions

kc_transaction_consensus_algorithm()

int kc_transaction_consensus_algorithm(
    const kc_transaction_t* transaction_ptr,
    tkc_consensus_algorithm* out_consensus_algo
)

Gets the consensus algorithm used by this transaction.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_consensus_algo - Pointer to consensus algorithm (output)

Returns: Error code (0 = success)

Example:

tkc_consensus_algorithm algorithm;
int result = kc_transaction_consensus_algorithm(transaction, &algorithm);
if (result == 0) {
    printf("Consensus algorithm: %d\n", algorithm);
}

kc_transaction_quorum()

int kc_transaction_quorum(
    const kc_transaction_t* transaction_ptr,
    kc_tag_set_t** out_quorum
)

Gets the quorum, which defines the set of participants and roles necessary for consensus.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_quorum - Pointer to quorum tag set pointer (output, caller must free)

Returns: Error code (0 = success)

Example:

kc_tag_set_t* quorum = NULL;
int result = kc_transaction_quorum(transaction, &quorum);
if (result == 0) {
    unsigned int quorum_size = 0;
    kc_tag_set_size(quorum, &quorum_size);
    printf("Consensus quorum has %u participants\n", quorum_size);

    // Check specific participant roles
    bool has_coordinator = false;
    kc_tag_set_has_key(quorum, "coordinator", &has_coordinator);
    if (has_coordinator) {
        char* coordinator_id = NULL;
        unsigned int id_size = 0;
        kc_tag_set_get_string(quorum, "coordinator", &coordinator_id, &id_size);
        printf("Coordinator: %.*s\n", id_size, coordinator_id);
        kc_common_delete_buffer(&coordinator_id);
    }

    kc_tag_set_destruct(&quorum);
}

Metadata Access Functions

kc_transaction_timestamp()

int kc_transaction_timestamp(
    const kc_transaction_t* transaction_ptr,
    uint64_t* out_timestamp
)

Gets the creation timestamp of the transaction.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_timestamp - Pointer to timestamp in milliseconds since epoch (output)

Returns: Error code (0 = success)

Example:

uint64_t timestamp = 0;
int result = kc_transaction_timestamp(transaction, &timestamp);
if (result == 0) {
    time_t creation_time = timestamp / 1000;
    printf("Transaction created: %s", ctime(&creation_time));
}

kc_transaction_version()

int kc_transaction_version(
    const kc_transaction_t* transaction_ptr,
    tkc_version* out_version
)

Gets the data format version of the transaction.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_version - Pointer to version information (output)

Returns: Error code (0 = success)

kc_transaction_data_type()

int kc_transaction_data_type(
    const kc_transaction_t* transaction_ptr,
    tkc_data_type* out_data_type
)

Gets the data type value indicating this is a transaction.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_data_type - Pointer to data type value (output)

Returns: Error code (0 = success)

Tag and Variable Functions

kc_transaction_tags()

int kc_transaction_tags(
    const kc_transaction_t* transaction_ptr,
    kc_tag_set_t** out_tags
)

Gets the immutable tag set containing transaction metadata.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_tags - Pointer to tags tag set pointer (output, caller must free)

Returns: Error code (0 = success)

Example:

kc_tag_set_t* tags = NULL;
int result = kc_transaction_tags(transaction, &tags);
if (result == 0) {
    // Check transaction type
    char* tx_type = NULL;
    unsigned int type_size = 0;
    kc_tag_set_get_string(tags, "transaction_type", &tx_type, &type_size);
    if (tx_type) {
        printf("Transaction type: %.*s\n", type_size, tx_type);
        kc_common_delete_buffer(&tx_type);
    }

    kc_tag_set_destruct(&tags);
}

kc_transaction_base_variables()

int kc_transaction_base_variables(
    const kc_transaction_t* transaction_ptr,
    kc_tag_set_t** out_base_variables
)

Gets the original variable tag set (stack variables at time index 0).

Parameters:

  • transaction_ptr - Transaction object to query

  • out_base_variables - Pointer to base variables tag set pointer (output, caller must free)

Returns: Error code (0 = success)

Example:

kc_tag_set_t* base_vars = NULL;
int result = kc_transaction_base_variables(transaction, &base_vars);
if (result == 0) {
    // Get initial state
    int64_t initial_value = 0;
    kc_tag_set_get_int64(base_vars, "counter", &initial_value);
    printf("Initial counter value: %lld\n", (long long)initial_value);

    kc_tag_set_destruct(&base_vars);
}

kc_transaction_stack_variables()

int kc_transaction_stack_variables(
    const kc_transaction_t* transaction_ptr,
    kc_tag_set_t** out_stack_variables,
    const unsigned int time_index
)

Gets the current merged stack variables at the specified time index.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_stack_variables - Pointer to stack variables tag set pointer (output, caller must free)

  • time_index - Time index (0 = initial variables, 1 = after first attestation, etc.)

Returns: Error code (0 = success)

Example:

// Get current state after all attestations
kc_attestation_t** attestations = NULL;
unsigned int attestation_count = 0;
kc_transaction_attestations(transaction, &attestations, &attestation_count);

kc_tag_set_t* current_vars = NULL;
int result = kc_transaction_stack_variables(transaction, &current_vars, attestation_count);
if (result == 0) {
    // Check current counter value
    int64_t current_value = 0;
    kc_tag_set_get_int64(current_vars, "counter", &current_value);
    printf("Current counter value: %lld\n", (long long)current_value);

    kc_tag_set_destruct(&current_vars);
}

// Cleanup attestations
if (attestations) {
    for (unsigned int i = 0; i < attestation_count; i++) {
        kc_attestation_destruct(&attestations[i]);
    }
    kc_common_delete_buffer_array((char**)&attestations, attestation_count);
}

Attestation Management Functions

kc_transaction_attestations()

int kc_transaction_attestations(
    const kc_transaction_t* transaction_ptr,
    kc_attestation_t*** out_attestation_ptr_array,
    unsigned int* num_attestations
)

Gets all attestations from the transaction.

Parameters:

  • transaction_ptr - Transaction object to query

  • out_attestation_ptr_array - Pointer to attestation array pointer (output, caller must free)

  • num_attestations - Pointer to number of attestations (output)

Returns: Error code (0 = success)

Example:

kc_attestation_t** attestations = NULL;
unsigned int attestation_count = 0;
int result = kc_transaction_attestations(transaction, &attestations, &attestation_count);
if (result == 0) {
    printf("Transaction has %u attestations:\n", attestation_count);

    for (unsigned int i = 0; i < attestation_count; i++) {
        unsigned int index = 0;
        uint64_t timestamp = 0;
        bool is_approval = false;

        kc_attestation_index(attestations[i], &index);
        kc_attestation_timestamp(attestations[i], &timestamp);
        kc_attestation_is_approval(attestations[i], &is_approval);

        time_t att_time = timestamp / 1000;
        printf("  [%u] %s at %s", index,
               is_approval ? "Approved" : "Rejected", ctime(&att_time));
    }

    // Cleanup
    for (unsigned int i = 0; i < attestation_count; i++) {
        kc_attestation_destruct(&attestations[i]);
    }
    kc_common_delete_buffer_array((char**)&attestations, attestation_count);
}

kc_transaction_reattach_attachable_attestation()

int kc_transaction_reattach_attachable_attestation(
    kc_transaction_t* transaction_ptr,
    const kc_attestation_t* attestation
)

Attaches an attachable attestation to the transaction.

Parameters:

  • transaction_ptr - Transaction object to modify

  • attestation - Attestation to attach

Returns: Error code (0 = success)

Example:

// Assume we have an attachable attestation from another context
kc_attestation_t* external_attestation = NULL;

// ... obtain external_attestation from somewhere ...

// Check if it's reattachable
bool is_reattachable = false;
kc_attestation_is_reattachable(external_attestation, &is_reattachable);

if (is_reattachable) {
    int result = kc_transaction_reattach_attachable_attestation(transaction, external_attestation);
    if (result == 0) {
        printf("Successfully reattached external attestation\n");
    } else {
        printf("Failed to reattach attestation: %d\n", result);
    }
} else {
    printf("Attestation is not reattachable\n");
}

Serialization Functions

kc_transaction_serialize()

int kc_transaction_serialize(
    const kc_transaction_t* transaction_ptr,
    char** out_serialized_string,
    unsigned int* out_size
)

Serializes the transaction to a string in protobuf format.

Parameters:

  • transaction_ptr - Transaction object to serialize

  • out_serialized_string - Pointer to serialized string pointer (output, caller must free)

  • out_size - Pointer to string size (output)

Returns: Error code (0 = success)

Example:

char* serialized = NULL;
unsigned int serialized_size = 0;
int result = kc_transaction_serialize(transaction, &serialized, &serialized_size);
if (result == 0) {
    printf("Serialized transaction (%u bytes): %.*s\n",
           serialized_size, serialized_size, serialized);
    kc_common_delete_buffer(&serialized);
}

Query Functions

kc_transaction_equals()

int kc_transaction_equals(
    const kc_transaction_t* lhs_transaction_ptr,
    bool* out_is_equal,
    const kc_transaction_t* rhs_transaction_ptr
)

Tests equality of two transaction objects.

Parameters:

  • lhs_transaction_ptr - First transaction to compare

  • out_is_equal - Pointer to equality result (output)

  • rhs_transaction_ptr - Second transaction to compare

Returns: Error code (0 = success)

Example: Consensus Process State Tracking

void demonstrate_consensus_tracking(kc_persona_t* coordinator) {
    // Create a transaction for a voting consensus
    kc_tag_set_t* quorum = NULL;
    kc_tag_set_t* base_vars = NULL;
    kc_tag_set_t* tags = NULL;

    // Define quorum participants
    int result = kc_tag_set_construct(&quorum);
    if (result != 0) return;

    kc_tag_set_add_string(quorum, "coordinator", "alice@company.com");
    kc_tag_set_add_string(quorum, "voter1", "bob@company.com");
    kc_tag_set_add_string(quorum, "voter2", "charlie@company.com");
    kc_tag_set_add_string(quorum, "voter3", "diana@company.com");
    kc_tag_set_add_int64(quorum, "required_votes", 3);

    // Set initial variables
    result = kc_tag_set_construct(&base_vars);
    if (result != 0) {
        kc_tag_set_destruct(&quorum);
        return;
    }

    kc_tag_set_add_string(base_vars, "proposal", "Increase development budget by 20%");
    kc_tag_set_add_int64(base_vars, "vote_count_yes", 0);
    kc_tag_set_add_int64(base_vars, "vote_count_no", 0);
    kc_tag_set_add_string(base_vars, "status", "voting");

    // Set transaction metadata
    result = kc_tag_set_construct(&tags);
    if (result != 0) {
        kc_tag_set_destruct(&quorum);
        kc_tag_set_destruct(&base_vars);
        return;
    }

    kc_tag_set_add_string(tags, "transaction_type", "consensus_vote");
    kc_tag_set_add_string(tags, "department", "Engineering");
    kc_tag_set_add_string(tags, "urgency", "high");

    // Create transaction (this would typically be done via persona functions)
    kc_transaction_t* voting_transaction = NULL;
    result = kc_persona_create_transaction(coordinator, &voting_transaction,
                                         TKC_CONSENSUS_ALGORITHM_RAFT,
                                         quorum, tags, base_vars);

    if (result == 0) {
        printf("Consensus voting transaction created\n");

        // Simulate voting process with attestations
        // (In practice, each voter would create attestations)

        // Check current state
        kc_tag_set_t* current_vars = NULL;
        unsigned int attestation_count = 0;
        kc_attestation_t** attestations = NULL;

        kc_transaction_attestations(voting_transaction, &attestations, &attestation_count);
        kc_transaction_stack_variables(voting_transaction, &current_vars, attestation_count);

        if (current_vars) {
            char* status = NULL;
            unsigned int status_size = 0;
            kc_tag_set_get_string(current_vars, "status", &status, &status_size);

            int64_t yes_votes = 0, no_votes = 0;
            kc_tag_set_get_int64(current_vars, "vote_count_yes", &yes_votes);
            kc_tag_set_get_int64(current_vars, "vote_count_no", &no_votes);

            printf("Current voting status: %.*s\n", status_size, status ? status : "unknown");
            printf("Votes: %lld yes, %lld no\n", (long long)yes_votes, (long long)no_votes);

            if (status) kc_common_delete_buffer(&status);
            kc_tag_set_destruct(&current_vars);
        }

        // Cleanup attestations
        if (attestations) {
            for (unsigned int i = 0; i < attestation_count; i++) {
                kc_attestation_destruct(&attestations[i]);
            }
            kc_common_delete_buffer_array((char**)&attestations, attestation_count);
        }

        kc_transaction_destruct(&voting_transaction);
    }

    kc_tag_set_destruct(&quorum);
    kc_tag_set_destruct(&base_vars);
    kc_tag_set_destruct(&tags);
}

Example: Transaction State History Analysis

void analyze_transaction_history(kc_transaction_t* transaction) {
    // Get total number of attestations
    kc_attestation_t** attestations = NULL;
    unsigned int attestation_count = 0;

    int result = kc_transaction_attestations(transaction, &attestations, &attestation_count);
    if (result != 0) {
        printf("Failed to get transaction attestations: %d\n", result);
        return;
    }

    printf("Analyzing transaction state history (%u attestations):\n", attestation_count);

    // Show initial state
    kc_tag_set_t* base_vars = NULL;
    result = kc_transaction_base_variables(transaction, &base_vars);
    if (result == 0) {
        printf("\nInitial state (time index 0):\n");
        char** keys = NULL;
        unsigned int key_count = 0;
        kc_tag_set_keys(base_vars, &keys, &key_count);

        for (unsigned int i = 0; i < key_count; i++) {
            char* value = NULL;
            unsigned int value_size = 0;
            if (kc_tag_set_get_string(base_vars, keys[i], &value, &value_size) == 0) {
                printf("  %s: %.*s\n", keys[i], value_size, value);
                kc_common_delete_buffer(&value);
            }
        }

        if (keys) kc_common_delete_buffer_array(&keys, key_count);
        kc_tag_set_destruct(&base_vars);
    }

    // Show state after each attestation
    for (unsigned int time_index = 1; time_index <= attestation_count; time_index++) {
        kc_tag_set_t* stack_vars = NULL;
        result = kc_transaction_stack_variables(transaction, &stack_vars, time_index);

        if (result == 0) {
            printf("\nState after attestation %u:\n", time_index);

            // Get attestation info
            kc_attestation_t* attestation = attestations[time_index - 1];
            bool is_approval = false;
            uint64_t timestamp = 0;

            kc_attestation_is_approval(attestation, &is_approval);
            kc_attestation_timestamp(attestation, &timestamp);

            time_t att_time = timestamp / 1000;
            printf("  Attestation: %s at %s",
                   is_approval ? "Approval" : "Rejection", ctime(&att_time));

            // Show variable changes
            char** keys = NULL;
            unsigned int key_count = 0;
            kc_tag_set_keys(stack_vars, &keys, &key_count);

            for (unsigned int i = 0; i < key_count; i++) {
                char* value = NULL;
                unsigned int value_size = 0;
                if (kc_tag_set_get_string(stack_vars, keys[i], &value, &value_size) == 0) {
                    printf("  %s: %.*s\n", keys[i], value_size, value);
                    kc_common_delete_buffer(&value);
                }
            }

            if (keys) kc_common_delete_buffer_array(&keys, key_count);
            kc_tag_set_destruct(&stack_vars);
        }
    }

    // Cleanup attestations
    for (unsigned int i = 0; i < attestation_count; i++) {
        kc_attestation_destruct(&attestations[i]);
    }
    kc_common_delete_buffer_array((char**)&attestations, attestation_count);

    printf("\nTransaction history analysis complete.\n");
}

Example: Consensus Algorithm Verification

bool verify_consensus_requirements(kc_transaction_t* transaction) {
    // Get consensus algorithm
    tkc_consensus_algorithm algorithm;
    int result = kc_transaction_consensus_algorithm(transaction, &algorithm);
    if (result != 0) {
        printf("Failed to get consensus algorithm\n");
        return false;
    }

    printf("Verifying consensus requirements for algorithm: %d\n", algorithm);

    // Get quorum requirements
    kc_tag_set_t* quorum = NULL;
    result = kc_transaction_quorum(transaction, &quorum);
    if (result != 0) {
        printf("Failed to get quorum information\n");
        return false;
    }

    // Check required participants
    int64_t required_votes = 0;
    bool has_required = kc_tag_set_get_int64(quorum, "required_votes", &required_votes) == 0;

    unsigned int quorum_size = 0;
    kc_tag_set_size(quorum, &quorum_size);

    printf("Quorum size: %u participants\n", quorum_size);
    if (has_required) {
        printf("Required votes: %lld\n", (long long)required_votes);
    }

    // Get attestations and check participation
    kc_attestation_t** attestations = NULL;
    unsigned int attestation_count = 0;
    kc_transaction_attestations(transaction, &attestations, &attestation_count);

    unsigned int approval_count = 0;
    unsigned int rejection_count = 0;

    for (unsigned int i = 0; i < attestation_count; i++) {
        bool is_approval = false;
        kc_attestation_is_approval(attestations[i], &is_approval);

        if (is_approval) {
            approval_count++;
        } else {
            rejection_count++;
        }
    }

    printf("Attestations: %u approvals, %u rejections\n", approval_count, rejection_count);

    // Verify consensus based on algorithm
    bool consensus_achieved = false;

    switch (algorithm) {
        case TKC_CONSENSUS_ALGORITHM_SIMPLE_MAJORITY:
            consensus_achieved = (approval_count > (quorum_size / 2));
            break;

        case TKC_CONSENSUS_ALGORITHM_UNANIMOUS:
            consensus_achieved = (approval_count == quorum_size) && (rejection_count == 0);
            break;

        case TKC_CONSENSUS_ALGORITHM_RAFT:
            if (has_required) {
                consensus_achieved = (approval_count >= required_votes);
            } else {
                consensus_achieved = (approval_count > (quorum_size / 2));
            }
            break;

        default:
            printf("Unknown consensus algorithm\n");
            break;
    }

    printf("Consensus achieved: %s\n", consensus_achieved ? "Yes" : "No");

    // Cleanup
    kc_tag_set_destruct(&quorum);
    if (attestations) {
        for (unsigned int i = 0; i < attestation_count; i++) {
            kc_attestation_destruct(&attestations[i]);
        }
        kc_common_delete_buffer_array((char**)&attestations, attestation_count);
    }

    return consensus_achieved;
}

Memory Management

  • Use kc_transaction_destruct() to free transaction objects

  • Use kc_tag_set_destruct() for tag sets returned by quorum, tags, and variable functions

  • Use kc_common_delete_buffer() for string outputs (serialized data)

  • Use kc_common_delete_buffer_array() for arrays of attestations

  • Always check return codes before using output parameters

Best Practices

  • Define clear quorum requirements before starting consensus processes

  • Use appropriate consensus algorithms for your use case

  • Track variable state changes through attestation sequences

  • Verify consensus requirements are met before considering transactions complete

  • Use immutable tags for transaction metadata and mutable variables for state

  • Store transaction history for audit and compliance purposes

See Also