-
Notifications
You must be signed in to change notification settings - Fork 286
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(core-p2p): transaction broadcaster (#3516)
- Loading branch information
Showing
14 changed files
with
180 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Container } from "@arkecosystem/core-kernel"; | ||
import { Interfaces } from "@arkecosystem/crypto"; | ||
|
||
import { TransactionBroadcaster } from "../../../packages/core-p2p/src/transaction-broadcaster"; | ||
|
||
describe("TransactionBroadcaster", () => { | ||
const container = new Container.Container(); | ||
|
||
describe("broadcastTransactions", () => { | ||
const logger = { warning: jest.fn(), debug: jest.fn() }; | ||
const configuration = { getRequired: jest.fn() }; | ||
const storage = { getPeers: jest.fn() }; | ||
const communicator = { postTransactions: jest.fn() }; | ||
|
||
beforeAll(() => { | ||
container.unbindAll(); | ||
container.bind(Container.Identifiers.LogService).toConstantValue(logger); | ||
container.bind(Container.Identifiers.PluginConfiguration).toConstantValue(configuration); | ||
container.bind(Container.Identifiers.PeerStorage).toConstantValue(storage); | ||
container.bind(Container.Identifiers.PeerCommunicator).toConstantValue(communicator); | ||
}); | ||
|
||
beforeEach(() => { | ||
logger.warning.mockReset(); | ||
logger.debug.mockReset(); | ||
configuration.getRequired.mockReset(); | ||
storage.getPeers.mockReset(); | ||
communicator.postTransactions.mockReset(); | ||
}); | ||
|
||
it("should warn when attempting to broadcast empty array", async () => { | ||
const broadcaster = container.resolve(TransactionBroadcaster); | ||
|
||
await broadcaster.broadcastTransactions([]); | ||
|
||
expect(logger.warning).toBeCalledWith("Broadcasting 0 transactions"); | ||
expect(configuration.getRequired).not.toBeCalled(); | ||
expect(storage.getPeers).not.toBeCalled(); | ||
expect(communicator.postTransactions).not.toBeCalled(); | ||
}); | ||
|
||
it("should broadcast transaction to peers", async () => { | ||
const peers = [{}, {}, {}]; | ||
configuration.getRequired.mockReturnValue(3); | ||
storage.getPeers.mockReturnValue(peers); | ||
const jsons = [{}]; | ||
const transactions: any[] = jsons.map(j => ({ toJson: jest.fn().mockReturnValue(j) })); | ||
|
||
const broadcaster = container.resolve(TransactionBroadcaster); | ||
await broadcaster.broadcastTransactions(transactions as Interfaces.ITransaction[]); | ||
|
||
expect(configuration.getRequired).toBeCalledWith("maxPeersBroadcast"); | ||
expect(storage.getPeers).toBeCalled(); | ||
expect(logger.debug).toBeCalledWith("Broadcasting 1 transaction to 3 peers"); | ||
expect(transactions[0].toJson).toBeCalled(); | ||
expect(communicator.postTransactions).toBeCalledWith(peers[0], jsons); | ||
expect(communicator.postTransactions).toBeCalledWith(peers[1], jsons); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Container } from "@arkecosystem/core-kernel"; | ||
import { Interfaces, Transactions } from "@arkecosystem/crypto"; | ||
|
||
import { Processor } from "../../../packages/core-transaction-pool/src/processor"; | ||
|
||
jest.mock("@arkecosystem/crypto"); | ||
|
||
describe("Processor", () => { | ||
const container = new Container.Container(); | ||
|
||
describe("process", () => { | ||
const logger = { warning: jest.fn() }; | ||
const pool = { addTransaction: jest.fn() }; | ||
const dynamicFeeMatcher = { canEnterPool: jest.fn(), canBroadcast: jest.fn() }; | ||
const transactionBroadcaster = { broadcastTransactions: jest.fn() }; | ||
|
||
beforeAll(() => { | ||
container.unbindAll(); | ||
container.bind(Container.Identifiers.LogService).toConstantValue(logger); | ||
container.bind(Container.Identifiers.TransactionPoolService).toConstantValue(pool); | ||
container.bind(Container.Identifiers.TransactionPoolDynamicFeeMatcher).toConstantValue(dynamicFeeMatcher); | ||
container.bind(Container.Identifiers.PeerTransactionBroadcaster).toConstantValue(transactionBroadcaster); | ||
}); | ||
|
||
beforeEach(() => { | ||
(Transactions.TransactionFactory.fromData as jest.Mock).mockReset(); | ||
|
||
logger.warning.mockReset(); | ||
pool.addTransaction.mockReset(); | ||
dynamicFeeMatcher.canEnterPool.mockReset(); | ||
dynamicFeeMatcher.canBroadcast.mockReset(); | ||
transactionBroadcaster.broadcastTransactions.mockReset(); | ||
}); | ||
|
||
it("should add eligible transactions to pool", async () => { | ||
(Transactions.TransactionFactory.fromData as jest.Mock).mockImplementation(d => ({ id: d.id })); | ||
|
||
dynamicFeeMatcher.canEnterPool.mockReturnValueOnce(true).mockReturnValueOnce(false); | ||
const data: any[] = [{ id: "id_eligible" }, { id: "id_non_eligible" }]; | ||
|
||
const processor = container.resolve(Processor); | ||
await processor.process(data as Interfaces.ITransactionData[]); | ||
|
||
expect(processor.accept).toEqual(["id_eligible"]); | ||
expect(processor.invalid).toEqual(["id_non_eligible"]); | ||
expect(processor.errors).toEqual({ | ||
id_non_eligible: { | ||
type: "ERR_LOW_FEE", | ||
message: "Transaction id_non_eligible fee is to low to include in pool", | ||
}, | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
packages/core-kernel/src/contracts/p2p/transaction-broadcaster.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Interfaces } from "@arkecosystem/crypto"; | ||
|
||
export interface TransactionBroadcaster { | ||
broadcastTransactions(transactions: Interfaces.ITransaction[]): Promise<void>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Container, Contracts, Providers, Utils } from "@arkecosystem/core-kernel"; | ||
import { Interfaces } from "@arkecosystem/crypto"; | ||
|
||
import { PeerCommunicator } from "./peer-communicator"; | ||
|
||
@Container.injectable() | ||
export class TransactionBroadcaster implements Contracts.P2P.TransactionBroadcaster { | ||
@Container.inject(Container.Identifiers.LogService) | ||
private readonly logger!: Contracts.Kernel.Logger; | ||
|
||
@Container.inject(Container.Identifiers.PluginConfiguration) | ||
@Container.tagged("plugin", "@arkecosystem/core-p2p") | ||
private readonly configuration!: Providers.PluginConfiguration; | ||
|
||
@Container.inject(Container.Identifiers.PeerStorage) | ||
private readonly storage!: Contracts.P2P.PeerStorage; | ||
|
||
@Container.inject(Container.Identifiers.PeerCommunicator) | ||
private readonly communicator!: PeerCommunicator; | ||
|
||
public async broadcastTransactions(transactions: Interfaces.ITransaction[]): Promise<void> { | ||
if (transactions.length === 0) { | ||
this.logger.warning("Broadcasting 0 transactions"); | ||
return; | ||
} | ||
|
||
const maxPeersBroadcast: number = this.configuration.getRequired<number>("maxPeersBroadcast"); | ||
const peers: Contracts.P2P.Peer[] = Utils.take(Utils.shuffle(this.storage.getPeers()), maxPeersBroadcast); | ||
|
||
const transactionsStr = Utils.pluralize("transaction", transactions.length, true); | ||
const peersStr = Utils.pluralize("peer", peers.length, true); | ||
this.logger.debug(`Broadcasting ${transactionsStr} to ${peersStr}`); | ||
|
||
const transactionsBroadcast: Interfaces.ITransactionJson[] = transactions.map(t => t.toJson()); | ||
const promises = peers.map(p => this.communicator.postTransactions(p, transactionsBroadcast)); | ||
|
||
await Promise.all(promises); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"extends": "./tsconfig.json", | ||
"exclude": ["node_modules"] | ||
} |