Files
skalacoin/src/block/transaction.c
T
dcrubro 763aeb648f 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.
2026-05-29 13:44:15 +02:00

109 lines
3.0 KiB
C

#include <block/transaction.h>
#include <string.h>
void Transaction_Init(signed_transaction_t* tx) {
if (!tx) { return; }
// Zero out everything
memset(tx, 0, sizeof(signed_transaction_t));
// NOTE: Other things might be added here
}
void Transaction_CalculateHash(const signed_transaction_t* tx, uint8_t* outHash) {
if (!tx || !outHash) {
return;
}
uint8_t buffer[sizeof(transaction_t)];
memcpy(buffer, &tx->transaction, sizeof(transaction_t));
SHA256(buffer, sizeof(buffer), outHash);
SHA256(outHash, 32, outHash); // Double-Hash
}
void Transaction_Sign(signed_transaction_t* tx, const uint8_t* privateKey) {
if (!tx || !privateKey) {
return;
}
uint8_t txHash[32];
Transaction_CalculateHash(tx, txHash);
Crypto_SignData(
txHash,
32,
privateKey,
tx->signature.signature
);
}
bool Transaction_Verify(const signed_transaction_t* tx) {
if (!tx) {
return false;
}
if (Address_IsCoinbase(tx->transaction.senderAddress)) {
if (tx->transaction.amount1 == 0) {
return false;
}
if (tx->transaction.amount2 != 0) {
return false;
}
if (Address_IsCoinbase(tx->transaction.recipientAddress1) || Address_IsCoinbase(tx->transaction.recipientAddress2)) {
return false;
}
uint8_t zeroAddress[32] = {0};
if (memcmp(tx->transaction.recipientAddress2, zeroAddress, 32) != 0) {
return false;
}
return true;
}
uint8_t computeAddress[32];
SHA256(tx->transaction.compressedPublicKey, 33, computeAddress); // Address is hash of public key
if (memcmp(computeAddress, tx->transaction.senderAddress, 32) != 0) {
return false; // Sender address does not match public key
}
if (tx->transaction.amount1 == 0) {
return false; // Zero-amount transactions are not valid
}
if (tx->transaction.fee > tx->transaction.amount1) {
return false; // Fee cannot exceed amount
}
if (tx->transaction.version != 1) {
return false; // Unsupported version
}
if (Address_IsCoinbase(tx->transaction.recipientAddress1) || Address_IsCoinbase(tx->transaction.recipientAddress2)) {
return false; // Cannot send to coinbase address
}
// Balance checks are stateful and are handled when a block is added to the chain.
// Transaction_Verify only checks transaction structure, addresses, and signature material.
if (tx->transaction.amount2 == 0) {
// If amount2 is zero, address2 must be all zeros
uint8_t zeroAddress[32] = {0};
if (memcmp(tx->transaction.recipientAddress2, zeroAddress, 32) != 0) {
return false; // amount2 is zero but address2 is not zeroed
}
}
uint8_t txHash[32];
Transaction_CalculateHash(tx, txHash);
// If all checks pass, verify the signature
return Crypto_VerifySignature(
txHash,
32,
tx->signature.signature,
tx->transaction.compressedPublicKey
);
}