From 17ef3b74fd1bed1bbade75bb2934941d4c1017db Mon Sep 17 00:00:00 2001 From: DcruBro Date: Fri, 29 May 2026 14:28:27 +0200 Subject: [PATCH] remove from mempool on mine; TEMPORARY log math proof of fee inclusion in coinbase tx --- include/txmempool.h | 2 ++ src/block/chain.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 58 +++++++++++++++++++++++++++++++++++- src/txmempool.c | 18 ++++++++++++ 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/include/txmempool.h b/include/txmempool.h index 05de667..18071ce 100644 --- a/include/txmempool.h +++ b/include/txmempool.h @@ -15,6 +15,8 @@ int TxMempool_Insert(signed_transaction_t tx); bool TxMempool_Lookup(uint8_t* txHash, signed_transaction_t* out); bool TxMempool_Snapshot(signed_transaction_t** outTxs, size_t* outCount); void TxMempool_Print(); +// Remove a transaction from the mempool by its hash. Returns true if removed. +bool TxMempool_Remove(const uint8_t* txHash); void TxMempool_Destroy(); #endif diff --git a/src/block/chain.c b/src/block/chain.c index 408bbdc..0f910a6 100644 --- a/src/block/chain.c +++ b/src/block/chain.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -243,8 +244,33 @@ bool Chain_AddBlock(blockchain_t* chain, block_t* block) { } expectedCoinbaseAmount += totalFees; + // Debug: log expected coinbase and fees to aid diagnosis when nodes disagree + { + uint64_t cbAmount = 0; + if (block->transactions && DynArr_size(block->transactions) > 0) { + signed_transaction_t* firstTx = (signed_transaction_t*)DynArr_at(block->transactions, 0); + if (firstTx && Address_IsCoinbase(firstTx->transaction.senderAddress)) { + cbAmount = firstTx->transaction.amount1; + } + } + char supplyStr[80]; + Uint256ToDecimal(¤tSupply, supplyStr, sizeof(supplyStr)); + printf("Chain_AddBlock: blockIndex=%zu expectedCoinbase=%llu totalFees=%llu observedBlockCoinbase=%llu currentReward=%llu currentSupply=%s\n", + expectedIndex, + (unsigned long long)expectedCoinbaseAmount, + (unsigned long long)totalFees, + (unsigned long long)cbAmount, + (unsigned long long)currentReward, + supplyStr); + } + uint64_t observedFees = 0; if (!Block_ValidateCoinbaseAndFees(block, expectedCoinbaseAmount, &observedFees) || observedFees != totalFees) { + // Log mismatch details for debugging + printf("Chain_AddBlock: validation failed: expectedCoinbase=%llu totalFees=%llu observedFees=%llu\n", + (unsigned long long)expectedCoinbaseAmount, + (unsigned long long)totalFees, + (unsigned long long)observedFees); free(spendableTxs); ok = false; break; @@ -294,6 +320,21 @@ bool Chain_AddBlock(blockchain_t* chain, block_t* block) { } } } + + // Remove mined non-coinbase transactions from the mempool so they are not re-mined or re-broadcast. + if (blk->transactions) { + for (size_t i = 0; i < DynArr_size(blk->transactions); ++i) { + signed_transaction_t* tx = (signed_transaction_t*)DynArr_at(blk->transactions, i); + if (!tx) continue; + if (Address_IsCoinbase(tx->transaction.senderAddress)) continue; + uint8_t txHash[32]; + Transaction_CalculateHash(tx, txHash); + if (TxMempool_Remove(txHash)) { + // optional: log removal + // printf("TxMempool_Remove: removed tx from mempool: "); PrintHexBytes(txHash, 32); printf("\n"); + } + } + } // ok remains true if no failures } while (0); @@ -304,6 +345,36 @@ bool Chain_AddBlock(blockchain_t* chain, block_t* block) { printf("Added new block to chain:\n"); Block_ShortPrint(block); + // After adding block, print a simple mathematical 'proof' that fees were included + { + uint64_t coinbaseAmount = 0; + uint64_t totalFees = 0; + if (block->transactions) { + for (size_t i = 0; i < DynArr_size(block->transactions); ++i) { + signed_transaction_t* tx = (signed_transaction_t*)DynArr_at(block->transactions, i); + if (!tx) { continue; } + if (Address_IsCoinbase(tx->transaction.senderAddress)) { + coinbaseAmount = tx->transaction.amount1; + } else { + if (UINT64_MAX - totalFees >= tx->transaction.fee) { + totalFees += tx->transaction.fee; + } + } + } + } + + uint64_t base = currentReward; + if (coinbaseAmount > 0 || totalFees > 0) { + printf("Proof: coinbase(%llu) == baseReward(%llu) + totalFees(%llu) => %llu == %llu + %llu\n", + (unsigned long long)coinbaseAmount, + (unsigned long long)base, + (unsigned long long)totalFees, + (unsigned long long)coinbaseAmount, + (unsigned long long)base, + (unsigned long long)totalFees); + } + } + return ok; } diff --git a/src/main.c b/src/main.c index 7232dea..9ccd580 100644 --- a/src/main.c +++ b/src/main.c @@ -429,6 +429,22 @@ static bool MineAndAppendBlock(blockchain_t* chain, } } + // Print mathematical proof that fees are included in the coinbase payout for miner visibility. + { + uint64_t cb = 0; + uint64_t fees = 0; + if (Block_GetCoinbaseAndFeeTotals(block, &cb, &fees)) { + uint64_t base = *currentReward; + printf("Mined block proof: coinbase(%llu) == baseReward(%llu) + totalFees(%llu) => %llu == %llu + %llu\n", + (unsigned long long)cb, + (unsigned long long)base, + (unsigned long long)fees, + (unsigned long long)cb, + (unsigned long long)base, + (unsigned long long)fees); + } + } + // After successfully appending a block, attempt to attach any orphans. size_t attached = OrphanPool_AttemptAttach(chain); if (attached > 0) { @@ -832,7 +848,7 @@ int main(int argc, char* argv[]) { char supplyStr[80]; Uint256ToDecimal(¤tSupply, supplyStr, sizeof(supplyStr)); printf("Current chain has %zu blocks, total supply %s\n", Chain_Size(chain), supplyStr); - printf("Commands: mine , send
[fee], balance [address], connect , sync (requires nodes), flushchain, fullverify, blockdetail , wipechain, genaddr, exit\n"); + printf("Commands: mine , send
[fee], txpooldetail , balance [address], connect , sync (requires nodes), flushchain, fullverify, blockdetail , wipechain, genaddr, exit\n"); char line[1024]; while (true) { @@ -1302,6 +1318,46 @@ int main(int argc, char* argv[]) { continue; } + if (strcmp(cmd, "txpooldetail") == 0) { + char* hashStr = strtok(NULL, " \t"); + if (!hashStr) { + printf("usage: txpooldetail \n"); + continue; + } + + uint8_t txHash[32]; + if (!ParseHexAddress32(hashStr, txHash)) { + printf("invalid tx hash: expected 64 hex chars\n"); + continue; + } + + signed_transaction_t tx; + if (!TxMempool_Lookup(txHash, &tx)) { + printf("transaction not found in mempool\n"); + continue; + } + + char senderHex[65]; + char recip1Hex[65]; + char recip2Hex[65]; + AddressToHexString(tx.transaction.senderAddress, senderHex); + AddressToHexString(tx.transaction.recipientAddress1, recip1Hex); + AddressToHexString(tx.transaction.recipientAddress2, recip2Hex); + + uint8_t calcHash[32]; + Transaction_CalculateHash(&tx, calcHash); + + printf("Transaction details:\n"); + printf(" TxHash: "); PrintHexBytes(calcHash, 32); printf("\n"); + printf(" Sender: %s%s\n", senderHex, Address_IsCoinbase(tx.transaction.senderAddress) ? " (coinbase)" : ""); + printf(" Recipient1: %s\n", recip1Hex); + printf(" Recipient2: %s\n", recip2Hex); + printf(" Amount1: %llu\n", (unsigned long long)tx.transaction.amount1); + printf(" Amount2: %llu\n", (unsigned long long)tx.transaction.amount2); + printf(" Fee: %llu\n", (unsigned long long)tx.transaction.fee); + continue; + } + } if (strcmp(cmd, "blockdetail") == 0) { diff --git a/src/txmempool.c b/src/txmempool.c index 6238b4a..6ac4bda 100644 --- a/src/txmempool.c +++ b/src/txmempool.c @@ -139,3 +139,21 @@ void TxMempool_Destroy() { g_txMempoolLockInitialized = false; } } + +bool TxMempool_Remove(const uint8_t* txHash) { + if (!txMempool || !txHash) { return false; } + + pthread_mutex_lock(&g_txMempoolLock); + key32_t key; + memcpy(key.bytes, txHash, 32); + + khiter_t k = kh_get(tx_mempool_map_m, txMempool, key); + if (k == kh_end(txMempool)) { + pthread_mutex_unlock(&g_txMempoolLock); + return false; + } + + kh_del(tx_mempool_map_m, txMempool, k); + pthread_mutex_unlock(&g_txMempoolLock); + return true; +}