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);
}
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, ×tamp);
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, ¤t_vars, attestation_count);
if (result == 0) {
// Check current counter value
int64_t current_value = 0;
kc_tag_set_get_int64(current_vars, "counter", ¤t_value);
printf("Current counter value: %lld\n", (long long)current_value);
kc_tag_set_destruct(¤t_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], ×tamp);
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, ¤t_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(¤t_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, ×tamp);
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
-
Attestation Functions - Individual consensus votes
-
Tag Set Functions - Quorum and variable storage
-
Persona Functions - Creating transactions
-
Verifiable Data - Base verifiable object functionality
-
Enums - Consensus algorithms and data types
-
C++ Transaction Class - Object-oriented interface