@nomiclabs/buidler
Version:
Buidler is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
115 lines (86 loc) • 2.87 kB
text/typescript
import { BN, bufferToHex, bufferToInt } from "ethereumjs-util";
export type Block = any;
export class Blockchain {
private readonly _blocks: Block[] = [];
private readonly _blockNumberByHash: Map<string, number> = new Map();
public getLatestBlock(cb: any): void {
if (this._blocks.length === 0) {
cb(new Error("No block available"));
}
cb(null, this._blocks[this._blocks.length - 1]);
}
public putBlock(block: any, cb: any): void {
const blockNumber = bufferToInt(block.header.number);
if (this._blocks.length !== blockNumber) {
cb(new Error("Invalid block number"));
return;
}
this._blocks.push(block);
this._blockNumberByHash.set(bufferToHex(block.hash()), blockNumber);
cb(null, block);
}
public delBlock(blockHash: Buffer, cb: any): void {
const blockNumber = this._blockNumberByHash.get(bufferToHex(blockHash));
if (blockNumber === undefined) {
cb(new Error("Block not found"));
return;
}
for (let n = blockNumber; n < this._blocks.length; n++) {
const block = this._blocks[n];
this._blockNumberByHash.delete(bufferToHex(block.hash()));
}
this._blocks.splice(blockNumber);
cb(null);
}
public getBlock(
hashOrBlockNumber: Buffer | BN,
cb: (err: Error | null, block?: Block) => void
): void {
let blockNumber: number;
if (BN.isBN(hashOrBlockNumber)) {
blockNumber = hashOrBlockNumber.toNumber();
} else {
const hash = bufferToHex(hashOrBlockNumber);
if (!this._blockNumberByHash.has(hash)) {
cb(new Error("Block not found"));
return;
}
blockNumber = this._blockNumberByHash.get(hash)!;
}
cb(null, this._blocks[blockNumber]);
}
public iterator(name: string, onBlock: any, cb: any): void {
let n = 0;
const iterate = (err?: Error | undefined | null) => {
if (err !== null || err !== undefined) {
cb(err);
return;
}
if (n >= this._blocks.length) {
cb(null);
return;
}
onBlock(this._blocks[n], false, (onBlockErr?: Error | null) => {
n += 1;
iterate(onBlockErr);
});
};
iterate(null);
}
public getDetails(_: string, cb: any): void {
cb(null);
}
public deleteAllFollowingBlocks(block: Block): void {
const blockNumber = bufferToInt(block.header.number);
const actualBlock = this._blocks[blockNumber];
if (actualBlock === undefined || !block.hash().equals(actualBlock.hash())) {
// tslint:disable-next-line only-buidler-error
throw new Error("Invalid block");
}
for (let i = blockNumber + 1; i < this._blocks.length; i++) {
const blockToDelete = this._blocks[i];
this._blockNumberByHash.delete(bufferToHex(blockToDelete.hash()));
}
this._blocks.splice(blockNumber + 1);
}
}