diff --git a/src/tx/validator.ts b/src/tx/validator.ts index 35db9b5ec9..75da556959 100644 --- a/src/tx/validator.ts +++ b/src/tx/validator.ts @@ -15,6 +15,7 @@ import { concatBuffers, isAccountNotFoundError, isKeyOfObject } from '../utils/o import { encode, Encoded, Encoding } from '../utils/encoder'; import Node, { TransformNodeType } from '../Node'; import { Account } from '../apis/node'; +import { genAggressiveCacheGetResponsesPolicy } from '../utils/autorest'; export interface ValidatorResult { message: string; @@ -68,16 +69,25 @@ const getSenderAddress = ( * to make sure it can be posted it to the chain * @category transaction builder * @param transaction - Base64Check-encoded transaction - * @param node - Node to validate transaction against + * @param nodeNotCached - Node to validate transaction against * @param parentTxTypes - Types of parent transactions * @returns Array with verification errors * @example const errors = await verifyTransaction(transaction, node) */ export default async function verifyTransaction( transaction: Encoded.Transaction | Encoded.Poi, - node: Node, + nodeNotCached: Node, parentTxTypes: Tag[] = [], ): Promise { + let node = nodeNotCached; + if ( + !node.pipeline.getOrderedPolicies() + .some(({ name }) => name === 'aggressive-cache-get-responses') + ) { + node = new Node(nodeNotCached.$host, { ignoreVersion: true }); + node.pipeline.addPolicy(genAggressiveCacheGetResponsesPolicy()); + } + const { tx, txType } = unpackTx(transaction); const address = getSenderAddress(tx) ?? (txType === Tag.SignedTx ? getSenderAddress(tx.encodedTx.tx) : undefined); diff --git a/src/utils/autorest.ts b/src/utils/autorest.ts index 76c634ab39..e60f6f4e83 100644 --- a/src/utils/autorest.ts +++ b/src/utils/autorest.ts @@ -31,7 +31,7 @@ export const genCombineGetRequestsPolicy = (): AdditionalPolicyConfig => { return { policy: { - name: 'combine-requests', + name: 'combine-get-requests', async sendRequest(request, next) { if (request.method !== 'GET') return next(request); const key = JSON.stringify([request.url, request.body]); @@ -48,6 +48,21 @@ export const genCombineGetRequestsPolicy = (): AdditionalPolicyConfig => { }; }; +export const genAggressiveCacheGetResponsesPolicy = (): PipelinePolicy => { + const getRequests = new Map>(); + + return { + name: 'aggressive-cache-get-responses', + async sendRequest(request, next) { + if (request.method !== 'GET') return next(request); + const key = JSON.stringify([request.url, request.body]); + const response = getRequests.get(key) ?? next(request); + getRequests.set(key, response); + return response; + }, + }; +}; + export const genErrorFormatterPolicy = ( getMessage: (b: any) => string, ): AdditionalPolicyConfig => ({ diff --git a/test/integration/chain.ts b/test/integration/chain.ts index 4c98f73313..cc75b94508 100644 --- a/test/integration/chain.ts +++ b/test/integration/chain.ts @@ -114,6 +114,21 @@ describe('Node Chain', () => { isConfirmed2.should.be.equal(true); }); + it('doesn\'t make extra requests', async () => { + const httpSpy = spy(http, 'request'); + await aeSdk.spend(100, publicKey, { waitMined: false, verify: false }); + expect(httpSpy.args.length).to.be.equal(2); // nonce, post tx + httpSpy.resetHistory(); + + await aeSdk.spend(100, publicKey, { waitMined: false, verify: false }); + expect(httpSpy.args.length).to.be.equal(2); // nonce, post tx + httpSpy.resetHistory(); + + await aeSdk.spend(100, publicKey, { waitMined: false }); + expect(httpSpy.args.length).to.be.equal(5); // nonce, validator(acc, height, status), post tx + httpSpy.restore(); + }); + const accounts = new Array(10).fill(undefined).map(() => MemoryAccount.generate()); const transactions: Encoded.TxHash[] = [];