fix(BlockchainInMemory): BIP30 protections and fetchChainTip

This commit is contained in:
Jim Hamill
2025-07-14 00:27:00 +00:00
parent b463207a2d
commit ed91b3f57b
@@ -23,8 +23,9 @@ import {
createVirtualMachineBCH,
} from '@bitauth/libauth';
// Local Blockchain Adapter.
// This simulates the BCH Blockchain.
/**
* @remarks This provider DOES NOT enforce the 100 confirmations Coinbase Transaction rule.
**/
export class BlockchainInMemory extends BaseBlockchain {
static async from<T extends typeof BlockchainInMemory>(this: T) {
const blockchain = new this();
@@ -104,10 +105,14 @@ export class BlockchainInMemory extends BaseBlockchain {
return blockHeader;
}
// TODO: Implement a method for fetching the chain tip.
// This is a placeholder for now.
async fetchChainTip(): Promise<BlockchainChainTip> {
throw new Error('Not implemented yet');
const height = this.blockHeaders.length;
const blockHeader = this.blockHeaders[height - 1];
return {
height,
blockHeader,
};
}
async broadcastTransaction(
@@ -347,14 +352,6 @@ export class BlockchainInMemory extends BaseBlockchain {
}
async mineBlock(outputs: Array<Output>): Promise<void> {
// Create a block header from the current timestamp.
const newBlockHeader = BlockHeader.generateRandom(
Math.floor(Date.now() / 1000),
);
// Add it to our list of block headers.
this.blockHeaders.push(newBlockHeader);
// Create a transaction that pays to our subscribed address.
const transaction = Transaction.fromRaw({
version: 2,
@@ -370,6 +367,24 @@ export class BlockchainInMemory extends BaseBlockchain {
outputs,
});
// Calculate the hash of this transaction.
const coinbaseTxHash = transaction.toHash();
// Ensure that this transaction hash does not already exist (as per BIP30).
if (this.transactions.has(coinbaseTxHash.toHex())) {
throw new Error(
`Transaction ID "${coinbaseTxHash.toHex()}" already exists (see BIP30 for details)`,
);
}
// Create a block header from the current timestamp.
const newBlockHeader = BlockHeader.generateRandom(
Math.floor(Date.now() / 1000),
);
// Add it to our list of block headers.
this.blockHeaders.push(newBlockHeader);
// Broadcast that transaction.
await this.broadcastTransaction(transaction, { skipValidation: true });
}