Skip to content

Commit

Permalink
chore(core-blockchain): check forged transactions in StateStore (#4408)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastijankuzner authored Jun 4, 2021
1 parent 6c62abe commit b158513
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 8 deletions.
50 changes: 48 additions & 2 deletions __tests__/unit/core-blockchain/processor/block-processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ describe("BlockProcessor", () => {
const roundState = {
getActiveDelegates: jest.fn().mockReturnValue([]),
};
const stateStore = {
getLastBlock: jest.fn(),
getLastBlocks: jest.fn(),
getLastStoredBlockHeight: jest.fn(),
};

const databaseInterceptor = {};

Expand All @@ -65,7 +70,7 @@ describe("BlockProcessor", () => {
sandbox.app.bind(Container.Identifiers.DatabaseInterceptor).toConstantValue(databaseInterceptor);
sandbox.app.bind(Container.Identifiers.RoundState).toConstantValue(roundState);
sandbox.app.bind(Container.Identifiers.TransactionHandlerRegistry).toConstantValue(transactionHandlerRegistry);
sandbox.app.bind(Container.Identifiers.StateStore).toConstantValue({});
sandbox.app.bind(Container.Identifiers.StateStore).toConstantValue(stateStore);
sandbox.app.bind(Container.Identifiers.TransactionPoolService).toConstantValue({});

sandbox.app.bind(Container.Identifiers.TriggerService).to(Services.Triggers.Triggers).inSingletonScope();
Expand Down Expand Up @@ -356,7 +361,7 @@ describe("BlockProcessor", () => {
});
});

it("should execute AlreadyForgedHandler when block has already forged transactions", async () => {
it("should execute AlreadyForgedHandler when block has already forged transactions in database", async () => {
const transactionData = {
id: "34821dfa9cbe59aad663b972326ff19265d788c4d4142747606aa29b19d6b1dab",
version: 2,
Expand All @@ -375,6 +380,47 @@ describe("BlockProcessor", () => {
getAttribute: jest.fn().mockReturnValue("generatorusername"),
};
walletRepository.findByPublicKey = jest.fn().mockReturnValueOnce(generatorWallet);
stateStore.getLastBlock.mockReturnValueOnce(baseBlock);
stateStore.getLastStoredBlockHeight.mockReturnValueOnce(baseBlock.data.height);
stateStore.getLastBlocks.mockReturnValueOnce([]);

const blockProcessor = sandbox.app.resolve<BlockProcessor>(BlockProcessor);

await blockProcessor.process(block);

expect(AlreadyForgedHandler.prototype.execute).toBeCalledTimes(1);
});

it("should execute AlreadyForgedHandler when block has already forged transactions in stateStore", async () => {
const transactionData = {
id: "34821dfa9cbe59aad663b972326ff19265d788c4d4142747606aa29b19d6b1dab",
version: 2,
senderPublicKey: "038082dad560a22ea003022015e3136b21ef1ffd9f2fd50049026cbe8e2258ca17",
nonce: Utils.BigNumber.make(2),
} as Interfaces.ITransactionData;
const transactionData2 = {
id: "34821dfa9cbe59aad663b972326ff19265d788c4d4142747606aa29b19d6b1dac",
version: 2,
senderPublicKey: "038082dad560a22ea003022015e3136b21ef1ffd9f2fd50049026cbe8e2258ca17",
nonce: Utils.BigNumber.make(3),
} as Interfaces.ITransactionData;
const block = {
...chainedBlock,
transactions: [{ data: transactionData, id: transactionData.id } as Interfaces.ITransaction],
};
roundState.getActiveDelegates = jest.fn().mockReturnValueOnce([]);
blockchain.getLastBlock = jest.fn().mockReturnValueOnce(baseBlock);
transactionRepository.getForgedTransactionsIds = jest.fn().mockReturnValueOnce([]);
walletRepository.getNonce = jest.fn().mockReturnValueOnce(Utils.BigNumber.ONE);
const generatorWallet = {
getAttribute: jest.fn().mockReturnValue("generatorusername"),
};
walletRepository.findByPublicKey = jest.fn().mockReturnValueOnce(generatorWallet);
stateStore.getLastBlock.mockReturnValueOnce({ data: { height: 2 } });
stateStore.getLastBlocks.mockReturnValueOnce([
{ data: { height: 2 }, transactions: [transactionData, transactionData2] },
]);
stateStore.getLastStoredBlockHeight.mockReturnValue(1);

const blockProcessor = sandbox.app.resolve<BlockProcessor>(BlockProcessor);

Expand Down
31 changes: 25 additions & 6 deletions packages/core-blockchain/src/processor/block-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export class BlockProcessor {
@Container.tagged("state", "blockchain")
private readonly walletRepository!: Contracts.State.WalletRepository;

@Container.inject(Container.Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;

@Container.inject(Container.Identifiers.TriggerService)
private readonly triggers!: Services.Triggers.Triggers;

Expand Down Expand Up @@ -123,13 +126,29 @@ export class BlockProcessor {

private async checkBlockContainsForgedTransactions(block: Interfaces.IBlock): Promise<boolean> {
if (block.transactions.length > 0) {
const forgedIds: string[] = await this.transactionRepository.getForgedTransactionsIds(
block.transactions.map((tx) => {
AppUtils.assert.defined<string>(tx.id);
const transactionIds = block.transactions.map((tx) => {
AppUtils.assert.defined<string>(tx.id);

return tx.id;
}),
);
return tx.id;
});

const forgedIds: string[] = await this.transactionRepository.getForgedTransactionsIds(transactionIds);

if (this.stateStore.getLastBlock().data.height !== this.stateStore.getLastStoredBlockHeight()) {
const transactionIdsSet = new Set<string>(transactionIds);

for (const stateBlock of this.stateStore
.getLastBlocks()
.filter((block) => block.data.height > this.stateStore.getLastStoredBlockHeight())) {
stateBlock.transactions.forEach((tx) => {
AppUtils.assert.defined<string>(tx.id);

if (transactionIdsSet.has(tx.id)) {
forgedIds.push(tx.id);
}
});
}
}

/* istanbul ignore else */
if (forgedIds.length > 0) {
Expand Down

0 comments on commit b158513

Please sign in to comment.