add fee-aware mining, coinbase validation, and reorg-safe orphan handling
Mining: blocks now include mempool txs, select spendable txs by fee, and pay coinbase as base reward + fees in main.c. - Consensus: block validation now enforces coinbase accounting and rejects invalid coinbase placement, including coinbase on amount2, in block.c and transaction.c. - Chain state: rollback now rebuilds currentSupply/currentReward, and block addition preflights spendability before mutating balances in chain.c. - Orphans/reorgs: orphan retry is safer, rollback-triggered sync reattaches orphans immediately, and transient orphan failures no longer drop blocks in orphan_pool.c and main.c. - Networking/mempool: node lifecycle now initializes the mempool, broadcasts can exclude one peer, and mempool snapshotting supports mining selection in net_node.c and txmempool.c. - Ledger simulation: added non-mutating spendable-transaction selection for block assembly in balance_sheet.c.
This commit is contained in:
+71
-6
@@ -214,23 +214,88 @@ bool Block_AllTransactionsValid(const block_t* block) {
|
||||
|
||||
for (size_t i = 0; i < DynArr_size(block->transactions); i++) {
|
||||
signed_transaction_t* tx = (signed_transaction_t*)DynArr_at(block->transactions, i);
|
||||
if (!Transaction_Verify(tx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tx && Address_IsCoinbase(tx->transaction.senderAddress)) {
|
||||
if (hasCoinbase) {
|
||||
return false; // More than one coinbase transaction
|
||||
return false;
|
||||
}
|
||||
|
||||
hasCoinbase = true;
|
||||
continue; // Coinbase transactions are valid since the miner has the right to create coins. Only rule is one per block.
|
||||
}
|
||||
|
||||
if (!Transaction_Verify(tx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true && hasCoinbase && DynArr_size(block->transactions) > 0; // Every block must have at least one transaction (the coinbase)
|
||||
}
|
||||
|
||||
bool Block_ValidateCoinbaseAndFees(const block_t* block, uint64_t expectedCoinbaseAmount, uint64_t* outTotalFees) {
|
||||
if (!block || !block->transactions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasCoinbase = false;
|
||||
uint64_t totalFees = 0;
|
||||
uint8_t zeroAddress[32] = {0};
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Address_IsCoinbase(tx->transaction.senderAddress)) {
|
||||
if (hasCoinbase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hasCoinbase = true;
|
||||
|
||||
if (!Transaction_Verify(tx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tx->transaction.fee != 0 || tx->transaction.amount2 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tx->transaction.amount1 != expectedCoinbaseAmount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Address_IsCoinbase(tx->transaction.recipientAddress1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(tx->transaction.recipientAddress2, zeroAddress, sizeof(zeroAddress)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Transaction_Verify(tx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UINT64_MAX - totalFees < tx->transaction.fee) {
|
||||
return false;
|
||||
}
|
||||
totalFees += tx->transaction.fee;
|
||||
}
|
||||
|
||||
if (!hasCoinbase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outTotalFees) {
|
||||
*outTotalFees = totalFees;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Block_IsFullyValid(const block_t* block) {
|
||||
bool merkleValid = false;
|
||||
uint8_t calculatedMerkleRoot[32];
|
||||
|
||||
Reference in New Issue
Block a user