Processing Transactions in Stable Shards
This tutorial guides developers through a TallyBox Windows desktop application that monitors stable database shards for new transactions and processes them using the `sql_ods_processor` function. The application uses a timer-based mechanism (`timer_engine_Tick`) to check sharded tables (`tbl_order_dispatcher_X`) and move new transactions to the `tbl_order_ods` table for processing. This tutorial explains the logic, algorithm, and data flow, with pseudo-code to aid implementation in a C# Windows Forms environment.
Step 1: Initialize Timer and Application State
The `timer_engine_Tick` function initializes the application state and sets up periodic shard checking. The process involves:
- Retrieve the current Unix timestamp (`local_utc_unix`) and update the UI (`txt_tree_local`).
- On first run (`Program.progress_utc_unix == 0`), set the progress timestamp to the current timestamp minus one and count existing jobs in `tbl_order_ods`.
- Log initialization messages using `AddText`.
Pseudo-Code: Initialize Timer
                
FUNCTION initialize_timer():
    local_utc_unix = get_current_unix_timestamp()
    update_ui(txt_tree_local, local_utc_unix)
    IF progress_utc_unix == 0 THEN
        progress_utc_unix = local_utc_unix - 1
        progress_in_ods = sql_count_records("tbl_order_ods", "the_sign")
        log_message("Box - ignites.. [" + progress_utc_unix + "]")
        log_message("ODS - scanner.. [" + progress_in_ods + "]")
    END IF
    RETURN local_utc_unix, progress_utc_unix, progress_in_ods
END FUNCTION
                
                
            Example Process:
                Current Timestamp: 1741675600
                UI Update: txt_tree_local = 1741675600
                Initial State: progress_utc_unix = 1741675599
                ODS Jobs: progress_in_ods = 5
                Log Output:
                Box - ignites.. [1741675599]
                ODS - scanner.. [5]
References:
                Timer Class (Microsoft Docs)
                Unix Time (Wikipedia)
            
Step 2: Check for Pending Jobs
If jobs exist in `tbl_order_ods` (`progress_in_ods > 0`), the `timer_engine_Tick` function triggers processing. The process involves:
- Log the busy state and number of remaining jobs.
- If `sql_ods_processor` is not running (`in_sql_ods_processor == false`), start it in a new thread.
Pseudo-Code: Check Pending Jobs
                
FUNCTION check_pending_jobs():
    IF progress_in_ods > 0 THEN
        log_message("Box - busy.. [" + progress_utc_unix + "] - job(s) remains: " + progress_in_ods)
        IF NOT in_sql_ods_processor THEN
            start_thread(sql_ods_processor)
        END IF
    END IF
END FUNCTION
                
                
            Example Process:
                progress_in_ods: 5
                in_sql_ods_processor: false
                Log Output: Box - busy.. [1741675599] - job(s) remains: 5
                Action: Start sql_ods_processor thread
References:
                Thread Class (Microsoft Docs)
                Multithreading (Wikipedia)
            
Step 3: Monitor Shards for New Transactions
If no jobs are pending, `timer_engine_Tick` checks sharded tables (`tbl_order_dispatcher_X`) for new transactions. The process involves:
- Increment `progress_utc_unix` and select the shard table based on its last digit (`dispatcher_line`).
- Check for records in the shard using `sql_find_record`.
- If records are found, move them to `tbl_order_ods` using `sql_move_record_extended` with a condition (`local_utc_unix <= progress_utc_unix`).
- Update `progress_in_ods` and log the number of moved jobs.
- Handle timestamp alignment (e.g., reset if ahead of current time).
Pseudo-Code: Monitor Shards
                
FUNCTION monitor_shards(local_utc_unix, progress_utc_unix):
    WHILE true:
        progress_utc_unix = progress_utc_unix + 1
        IF local_utc_unix - progress_utc_unix == 1 THEN
            log_message("Box - listens.. [" + progress_utc_unix + "]")
            BREAK
        ELSE IF local_utc_unix - progress_utc_unix < 1 THEN
            progress_utc_unix = progress_utc_unix - 1
            log_message("Box - exception.. [" + progress_utc_unix + "]")
            BREAK
        ELSE
            log_message("Box - jumps.. [" + progress_utc_unix + "]")
        END IF
        dispatcher_line = last_digit(progress_utc_unix)
        job_found = sql_find_record("tbl_order_dispatcher_" + dispatcher_line, "the_sign")
        IF job_found != "no_record" THEN
            jobs_moved = sql_move_records("tbl_order_dispatcher_" + dispatcher_line,
                                          "tbl_order_ods",
                                          "graph_from,graph_to,wallet_from,wallet_to,order_currency,order_amount,order_utc_unix,order_id,public_key,the_sign,local_utc_unix",
                                          "local_utc_unix<=" + progress_utc_unix)
            IF jobs_moved > 0 THEN
                log_message("dispatcher[" + dispatcher_line + "][" + jobs_moved + "] moved to ods..")
                progress_in_ods = sql_count_records("tbl_order_ods", "the_sign")
                log_message("- job(s) found: " + progress_in_ods)
                BREAK
            END IF
        END IF
    END WHILE
    update_ui(txt_tree_progress, progress_utc_unix)
    update_ui(txt_dispatcher_line, dispatcher_line)
    update_ui(txt_ods_jobs, progress_in_ods)
END FUNCTION
                
                
            Example Process:
                local_utc_unix: 1741675600
                progress_utc_unix: 1741675599
                dispatcher_line: 9
                Job Found: the_sign = MEYCIQCxzNKhOUXijLr+z2mI9npu/+KZijiEv3//W7Ya3VpvzgIhAI1m7wJLJ9ldP2m5jmYfUreuvoKTjoZmFQmt5e6foakp
                Jobs Moved: 3
                Log Output:
                Box - listens.. [1741675599]
                dispatcher[9][3] moved to ods..
                - job(s) found: 3
                UI Update:
                txt_tree_progress = 1741675599
                txt_dispatcher_line = 9
                txt_ods_jobs = 3
References:
                SQL INSERT Statement (Microsoft Docs)
                Database Sharding (Wikipedia)
            
Step 4: Process ODS Records
The `sql_ods_processor` function processes records from `tbl_order_ods`, performing validation and ledger updates. The process involves:
- Query `tbl_order_ods` for records, ordered by `local_utc_unix`.
- For each record, extract fields (e.g., `graph_from`, `wallet_from`, `order_currency`).
- Decrement `progress_in_ods` to track remaining jobs.
- Validate formats, graph domains, currency, and signatures, marking invalid records for deletion.
- Handle treasury (`$`) and group (`#`) transactions with specific checks.
Pseudo-Code: Process ODS Records
                
FUNCTION sql_ods_processor():
    in_sql_ods_processor = true
    records = sql_query("SELECT * FROM tbl_order_ods ORDER BY local_utc_unix")
    IF records.is_empty THEN
        in_sql_ods_processor = false
        RETURN
    END IF
    FOR EACH record IN records:
        progress_in_ods = progress_in_ods - 1
        order_data = extract_fields(record, ["graph_from", "graph_to", "wallet_from", "wallet_to", 
                                             "order_currency", "order_amount", "order_utc_unix", 
                                             "order_id", "public_key", "the_sign", "local_utc_unix"])
        delete_record = validate_record(order_data)
        IF delete_record THEN
            sql_delete("tbl_order_ods", "the_sign='" + order_data.the_sign + "'")
            sql_delete("tbl_order_ods_multiple", "the_sign_md5='" + hash_md5(order_data.the_sign) + "'")
            CONTINUE
        END IF
        // Proceed to further processing (next steps)
    END FOR
END FUNCTION
                
                
            Example Process:
                Query: SELECT * FROM tbl_order_ods ORDER BY local_utc_unix
                Record: graph_from=tallybox.mixoftix.net, wallet_from=boxB2bbc15c8c135..., order_currency=2ZR, order_amount=3500.00000000
                progress_in_ods: 4 (after decrement)
                Validation: All formats valid
                Result: Proceed to next steps
References:
                SqlDataReader (Microsoft Docs)
                SQL (Wikipedia)
            
Step 5: Validate Transactions
Validate each transaction’s format, database records, treasury/group details, and signature. The process involves:
- Check formats: Ensure `graph_from`/`graph_to` contain dots, wallets are valid, and timestamps/amounts are numeric.
- Verify graph domains and currency in database tables (`tbl_system_graph`, `tbl_system_currency`).
- For treasury transactions (`order_id` starts with `$`): Validate treasury ID, check for double-spending, and match currency/amount/wallet.
- For group transactions (`order_id` starts with `#`): Validate multiple recipients and amounts, check for duplicates, and verify total amount.
- Verify ECDSA signature using `secp256r1` curve.
Pseudo-Code: Validate Transactions
                
FUNCTION validate_record(order_data):
    delete_record = false
    IF NOT contains(order_data.graph_from, ".") OR NOT contains(order_data.graph_to, ".") THEN
        log_message("check format failed: graph")
        delete_record = true
    END IF
    IF NOT wallet_qc(order_data.wallet_from) OR (NOT order_data.order_id.starts_with("#") AND NOT wallet_qc(order_data.wallet_to)) THEN
        log_message("check format failed: wallet")
        delete_record = true
    END IF
    IF NOT isnumeric(order_data.order_utc_unix) OR NOT isnumeric(order_data.local_utc_unix) THEN
        log_message("check format failed: timestamp")
        delete_record = true
    END IF
    IF graph_id_from = sql_find_record("tbl_system_graph", "graph_id", "graph_domain", order_data.graph_from) == "no_record" THEN
        log_message("error~207~invalid graph~graph_from")
        delete_record = true
    END IF
    IF graph_id_to = sql_find_record("tbl_system_graph", "graph_id", "graph_domain", order_data.graph_to) == "no_record" THEN
        log_message("error~207~invalid graph~graph_to")
        delete_record = true
    END IF
    IF currency_id = sql_find_record("tbl_system_currency", "currency_id", "currency_name", order_data.order_currency) == "no_record" THEN
        log_message("not found (currency_name): " + order_data.order_currency)
        delete_record = true
    END IF
    the_sign_md5 = hash_md5(order_data.the_sign)
    IF order_data.order_id.starts_with("$") THEN
        treasury_id = sql_find_record("tbl_system_treasury", "treasury_id", "treasury_id", order_data.order_id)
        IF treasury_id == "no_record" OR sql_find_record("tbl_tallybox_sign", "order_id", "order_id", treasury_id) != "no_record" THEN
            log_message("error~204 or 205~treasury error")
            delete_record = true
        ELSE IF treasury details mismatch THEN
            log_message("error~206~treasury mismatch error")
            delete_record = true
        END IF
    ELSE IF order_data.order_id.starts_with("#") THEN
        num_tnxs = sql_max_field_id("tbl_order_ods_multiple", "row_id", "the_sign_md5", the_sign_md5) OR 1
        IF check_duplicate(the_sign_md5) THEN
            delete_record = true
        END IF
        FOR i = 1 TO num_tnxs:
            wallet_to = sql_find_record_with_where("tbl_order_ods_multiple", "wallet_to", "row_id='" + i + "' and the_sign_md5='" + the_sign_md5 + "'")
            order_amount = sql_find_record_with_where("tbl_order_ods_multiple", "order_amount", "row_id='" + i + "' and the_sign_md5='" + the_sign_md5 + "'")
            IF NOT wallet_qc(wallet_to) OR NOT isnumeric(order_amount) THEN
                delete_record = true
            END IF
        END FOR
    ELSE IF NOT order_data.order_id.is_empty AND NOT isnumeric(order_data.order_id) THEN
        log_message("warning~503~invalid numeric data~order_id")
        order_data.order_id = ""
    END IF
    IF NOT order_data.order_id.starts_with("#") AND NOT isnumeric(order_data.order_amount) THEN
        log_message("error~303~invalid numeric data~order_amount")
        delete_record = true
    END IF
    order_string = join([order_data.graph_from, order_data.graph_to, order_data.wallet_from, 
                         order_data.wallet_to, order_data.order_currency, order_data.order_amount, 
                         order_data.order_id, order_data.order_utc_unix], "~")
    public_key_decompressed = decompress_b58_in_b58_out(order_data.public_key.replace("*", "~"), "secp256r1")
    IF NOT sign_data_b64_check(order_string, order_data.the_sign, public_key_decompressed, "secp256r1") THEN
        log_message("error mis-match (ecc_sign)")
        delete_record = true
    END IF
    RETURN delete_record
END FUNCTION
                
                
            Example Process:
                order_id: 778844 (Numeric, single transaction)
                graph_from: tallybox.mixoftix.net (Valid)
                wallet_from: boxB2bbc15c8c135... (Valid)
                order_currency: 2ZR (Valid in tbl_system_currency)
                order_amount: 3500.00000000 (Numeric)
                Signature: Valid
                Result: delete_record = false
References:
                ECDSA Algorithm (Wikipedia)
                Double-Spending (Wikipedia)
            
Step 6: Update Ledger and Wallets
For valid transactions, update wallet records and ledger entries. The process involves:
- Generate a unique transaction ID (`tnx_id`) using a tree-branch structure (`tree_id.local_utc_unix.branch_id_reverse`).
- Register new wallets (`wallet_from`, `wallet_to`) in `tbl_tallybox_wallet` and `tbl_tallybox_wallet_pubkey`, with buffer tables.
- Calculate fees (2 * 250.0 IRR + num_tnxs * 250.0 IRR) and update sender’s balance in `tbl_tallybox_book`.
- Update sender and receiver balances for the transaction amount in `tbl_tallybox_book`.
- Record the signature in `tbl_tallybox_sign` with a transaction hash.
- Delete processed records from `tbl_order_ods` and `tbl_order_ods_multiple`.
Pseudo-Code: Update Ledger and Wallets
                
FUNCTION update_ledger_and_wallets(order_data, num_tnxs, wallet_to_arr, order_amount_arr):
    tree_id = order_data.local_utc_unix
    row_number = increment_row_number(tree_id)
    branch_id = row_number
    branch_id_reverse = reverse(branch_id)
    tnx_id = tree_id + "." + branch_id_reverse
    session_wallet_id = sql_max_field_id("tbl_tallybox_wallet", "wallet_id")
    wallet_from_id = register_wallet(order_data.wallet_from, session_wallet_id)
    register_public_key(order_data.public_key, wallet_from_id)
    FOR j = 0 TO num_tnxs - 1:
        wallet_to_id_arr[j] = register_wallet(wallet_to_arr[j], session_wallet_id)
    END FOR
    currency_id_fee = "1"
    currency_amount_fee = (2 * base_fee_amount) + (num_tnxs * base_fee_amount)
    left_amount_fee = calculate_balance(order_data.graph_from, wallet_from_id, currency_id_fee, currency_amount_fee)
    tally_hash_fee = hash_sha256(previous_tally_hash + components)
    sql_insert("tbl_tallybox_book", fee_entry)
    sql_insert("tbl_tallybox_book_buffer", fee_entry, archive_id="1")
    sql_insert("tbl_tallybox_book_buffer", fee_entry, archive_id="2")
    left_amount_from = calculate_balance(order_data.graph_from, wallet_from_id, currency_id, order_data.order_amount)
    tally_hash_from = hash_sha256(previous_tally_hash + components)
    sql_insert("tbl_tallybox_book", from_entry)
    sql_insert("tbl_tallybox_book_buffer", from_entry, archive_id="1")
    sql_insert("tbl_tallybox_book_buffer", from_entry, archive_id="2")
    FOR j = 0 TO num_tnxs - 1:
        left_amount_to = calculate_balance(order_data.graph_to, wallet_to_id_arr[j], currency_id, order_amount_arr[j])
        tally_hash_to = hash_sha256(previous_tally_hash + components)
        sql_insert("tbl_tallybox_book", to_entry[j])
        sql_insert("tbl_tallybox_book_buffer", to_entry[j], archive_id="1")
        sql_insert("tbl_tallybox_book_buffer", to_entry[j], archive_id="2")
    END FOR
    tnx_md5 = hash_md5(hash_sha256(tally_hash_fee + tally_hash_from + tally_hash_to))
    sql_insert("tbl_tallybox_sign", signature_entry)
    sql_insert("tbl_tallybox_sign_buffer", signature_entry, archive_id="1")
    sql_insert("tbl_tallybox_sign_buffer", signature_entry, archive_id="2")
    sql_delete("tbl_order_ods", "the_sign='" + order_data.the_sign + "'")
    sql_delete("tbl_order_ods_multiple", "the_sign_md5='" + hash_md5(order_data.the_sign) + "'")
END FUNCTION
                
                
            Example Output:
				
References:
                SHA-256 Algorithm (Wikipedia)
                MD5 Algorithm (Wikipedia)
            
Acknowledgments
Special thanks to Grok, for its invaluable assistance in creating this TallyBox transaction shard processing tutorial.