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.
142 lines
3.8 KiB
C
142 lines
3.8 KiB
C
#include <txmempool.h>
|
|
#include <pthread.h>
|
|
|
|
static pthread_mutex_t g_txMempoolLock;
|
|
static bool g_txMempoolLockInitialized = false;
|
|
|
|
khash_t(tx_mempool_map_m)* txMempool = NULL;
|
|
|
|
void TxMempool_Init() {
|
|
txMempool = kh_init(tx_mempool_map_m);
|
|
pthread_mutex_init(&g_txMempoolLock, NULL);
|
|
g_txMempoolLockInitialized = true;
|
|
}
|
|
|
|
int TxMempool_Insert(signed_transaction_t tx) {
|
|
if (!txMempool) { return -1; }
|
|
|
|
pthread_mutex_lock(&g_txMempoolLock);
|
|
uint8_t txHash[32];
|
|
Transaction_CalculateHash(&tx, txHash);
|
|
|
|
key32_t key;
|
|
memcpy(key.bytes, txHash, 32);
|
|
|
|
int ret;
|
|
khiter_t k = kh_put(tx_mempool_map_m, txMempool, key, &ret);
|
|
if (k == kh_end(txMempool)) {
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
return -1;
|
|
}
|
|
|
|
kh_value(txMempool, k) = tx;
|
|
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool TxMempool_Lookup(uint8_t* txHash, signed_transaction_t* out) {
|
|
if (!txMempool || !txHash || !out) { 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)) {
|
|
signed_transaction_t tx = kh_value(txMempool, k);
|
|
memcpy(out, &tx, sizeof(signed_transaction_t));
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
return true;
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
return false;
|
|
}
|
|
|
|
bool TxMempool_Snapshot(signed_transaction_t** outTxs, size_t* outCount) {
|
|
if (!outTxs || !outCount) {
|
|
return false;
|
|
}
|
|
|
|
*outTxs = NULL;
|
|
*outCount = 0;
|
|
|
|
if (!txMempool) {
|
|
return true;
|
|
}
|
|
|
|
pthread_mutex_lock(&g_txMempoolLock);
|
|
|
|
size_t count = 0;
|
|
khiter_t k;
|
|
for (k = kh_begin(txMempool); k != kh_end(txMempool); ++k) {
|
|
if (kh_exist(txMempool, k)) {
|
|
++count;
|
|
}
|
|
}
|
|
|
|
if (count == 0) {
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
return true;
|
|
}
|
|
|
|
signed_transaction_t* snapshot = (signed_transaction_t*)malloc(count * sizeof(signed_transaction_t));
|
|
if (!snapshot) {
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
return false;
|
|
}
|
|
|
|
size_t index = 0;
|
|
for (k = kh_begin(txMempool); k != kh_end(txMempool); ++k) {
|
|
if (kh_exist(txMempool, k)) {
|
|
snapshot[index++] = kh_value(txMempool, k);
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
|
|
*outTxs = snapshot;
|
|
*outCount = count;
|
|
return true;
|
|
}
|
|
|
|
void TxMempool_Print() {
|
|
if (!txMempool) { return; }
|
|
|
|
pthread_mutex_lock(&g_txMempoolLock);
|
|
khiter_t k;
|
|
for (k = kh_begin(txMempool); k != kh_end(txMempool); ++k) {
|
|
if (kh_exist(txMempool, k)) {
|
|
signed_transaction_t tx = kh_val(txMempool, k);
|
|
char senderHex[65];
|
|
char recipient1Hex[65];
|
|
char recipient2Hex[65];
|
|
AddressToHexString(tx.transaction.senderAddress, senderHex);
|
|
AddressToHexString(tx.transaction.recipientAddress1, recipient1Hex);
|
|
AddressToHexString(tx.transaction.recipientAddress2, recipient2Hex);
|
|
printf("TX in mempool: sender=%s recipient1=%s recipient2=%s amount1=%llu amount2=%llu fee=%llu\n",
|
|
senderHex, recipient1Hex, recipient2Hex,
|
|
(unsigned long long)tx.transaction.amount1,
|
|
(unsigned long long)tx.transaction.amount2,
|
|
(unsigned long long)tx.transaction.fee);
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
}
|
|
|
|
void TxMempool_Destroy() {
|
|
if (txMempool) {
|
|
pthread_mutex_lock(&g_txMempoolLock);
|
|
kh_destroy(tx_mempool_map_m, txMempool);
|
|
txMempool = NULL;
|
|
pthread_mutex_unlock(&g_txMempoolLock);
|
|
}
|
|
|
|
if (g_txMempoolLockInitialized) {
|
|
pthread_mutex_destroy(&g_txMempoolLock);
|
|
g_txMempoolLockInitialized = false;
|
|
}
|
|
}
|