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.
109 lines
3.0 KiB
C
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
|
|
);
|
|
}
|