@0x:contracts-integrations
Removed the Cache
This commit is contained in:
parent
c87364f86b
commit
03e35846fb
@ -1,4 +1,4 @@
|
||||
/*import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, expect } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { artifacts, TestFrameworkContract } from '../../src';
|
||||
@ -73,4 +73,3 @@ blockchainTests('TestFramework', env => {
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
@ -1,10 +1,20 @@
|
||||
/*import { blockchainTests, constants, expect, filterLogsToArguments, hexRandom } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, generatePseudoRandom256BitNumber } from '@0x/utils';
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexRandom,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
|
||||
import { artifacts, TestFrameworkContract, TestFrameworkSomeEventEventArgs, TestFrameworkEvents } from '../../src';
|
||||
import { FunctionAssertion, Result } from '../utils/function_assertions';
|
||||
|
||||
const ZERO = constants.ZERO_AMOUNT;
|
||||
const MAX_UINT256 = constants.MAX_UINT256;
|
||||
|
||||
blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
let exampleContract: TestFrameworkContract;
|
||||
|
||||
@ -19,7 +29,7 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
|
||||
describe('runAsync', () => {
|
||||
it('should call the before function with the provided arguments', async () => {
|
||||
let sideEffectTarget = constants.ZERO_AMOUNT;
|
||||
let sideEffectTarget = ZERO;
|
||||
const assertion = new FunctionAssertion(exampleContract.noEffect, {
|
||||
before: async (inputValue: BigNumber) => {
|
||||
sideEffectTarget = inputValue;
|
||||
@ -27,13 +37,13 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => {},
|
||||
});
|
||||
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
await assertion.runAsync(randomInput);
|
||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||
});
|
||||
|
||||
it('should call the after function with the provided arguments', async () => {
|
||||
let sideEffectTarget = constants.ZERO_AMOUNT;
|
||||
let sideEffectTarget = ZERO;
|
||||
const assertion = new FunctionAssertion(exampleContract.noEffect, {
|
||||
before: async (inputValue: BigNumber) => {},
|
||||
after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => {
|
||||
@ -41,7 +51,7 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
},
|
||||
});
|
||||
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
await assertion.runAsync(randomInput);
|
||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||
});
|
||||
@ -52,12 +62,12 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
before: async (inputValue: BigNumber) => {},
|
||||
after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => {},
|
||||
});
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
await assertion.runAsync(randomInput);
|
||||
});
|
||||
|
||||
it('should pass the return value from "before" to "after"', async () => {
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
let sideEffectTarget = constants.ZERO_AMOUNT;
|
||||
const assertion = new FunctionAssertion(exampleContract.noEffect, {
|
||||
before: async (inputValue: BigNumber) => {
|
||||
@ -79,13 +89,13 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
sideEffectTarget = result.data;
|
||||
},
|
||||
});
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
await assertion.runAsync(randomInput);
|
||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||
});
|
||||
|
||||
it('should pass the receipt from the function call to "after"', async () => {
|
||||
let sideEffectTarget: TransactionReceiptWithDecodedLogs = {} as TransactionReceiptWithDecodedLogs;
|
||||
let sideEffectTarget = {} as TransactionReceiptWithDecodedLogs;
|
||||
const assertion = new FunctionAssertion(exampleContract.revertSideEffect, {
|
||||
before: async (inputValue: BigNumber) => {},
|
||||
after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => {
|
||||
@ -96,7 +106,7 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
}
|
||||
},
|
||||
});
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
await assertion.runAsync(randomInput);
|
||||
|
||||
// Ensure that the correct events were emitted.
|
||||
@ -116,11 +126,10 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
||||
sideEffectTarget = result.data;
|
||||
},
|
||||
});
|
||||
const randomInput = generatePseudoRandom256BitNumber();
|
||||
const randomInput = getRandomInteger(ZERO, MAX_UINT256);
|
||||
await assertion.runAsync(randomInput);
|
||||
const errorMessage = 'VM Exception while processing transaction: revert Revert';
|
||||
expect(sideEffectTarget.message).to.be.eq(errorMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
@ -1,155 +0,0 @@
|
||||
import { blockchainTests, constants, expect, hexSlice } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BlockParam, CallData } from 'ethereum-types';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { artifacts, TestFrameworkContract } from '../../src';
|
||||
import { GetterCache } from '../utils/cache';
|
||||
|
||||
blockchainTests.resets('Cache Tests', env => {
|
||||
let exampleContract: TestFrameworkContract;
|
||||
|
||||
before(async () => {
|
||||
exampleContract = await TestFrameworkContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestFramework,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('callAsync', () => {
|
||||
describe('() => uint', () => {
|
||||
let cache: GetterCache;
|
||||
|
||||
beforeEach(async () => {
|
||||
cache = new GetterCache(exampleContract.numberSideEffect);
|
||||
});
|
||||
|
||||
it('should return 0 when "counter" == 0', async () => {
|
||||
expect(await cache.callAsync()).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('should return 1 when "counter" == 1', async () => {
|
||||
// Update the counter to 1.
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
|
||||
// Ensure that the returned value is the updated counter.
|
||||
expect(await cache.callAsync()).bignumber.to.be.eq(new BigNumber(1));
|
||||
});
|
||||
|
||||
it('should return the cached counter', async () => {
|
||||
// Cache a value.
|
||||
expect(await cache.callAsync()).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
|
||||
// Update the counter to 1.
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
|
||||
// This should return "0" because a value was cached by the first call to "callAsync"
|
||||
expect(await cache.callAsync()).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('uint => boolean', () => {
|
||||
let cache: GetterCache;
|
||||
|
||||
beforeEach(async () => {
|
||||
cache = new GetterCache(exampleContract.equalsSideEffect);
|
||||
});
|
||||
|
||||
it('should return true when "possiblyZero" == 0 && "counter" == 0', async () => {
|
||||
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when "possiblyZero" == 0 && "counter" != 0', async () => {
|
||||
// Update "counter" to "1", which will cause all calls to return false.
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.false();
|
||||
});
|
||||
|
||||
it('should return the cached value', async () => {
|
||||
// Cache a "true" value when "possiblyZero" == 0 && "counter" == 0
|
||||
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
|
||||
|
||||
// Update "counter" to "1", which will cause all calls of "isZeroOrFalse" to return "false".
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
|
||||
// This should return "true" because a value was by the first call to "callAsync"
|
||||
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('(uint, bytes32) => bytes32', () => {
|
||||
let cache: GetterCache;
|
||||
|
||||
beforeEach(async () => {
|
||||
cache = new GetterCache(exampleContract.hashSideEffect);
|
||||
});
|
||||
|
||||
it('should return correct hash when counter == 0', async () => {
|
||||
// Get the calldata for the function call, which includes the abi-encoded data to hash.
|
||||
const hashData = exampleContract.hashSideEffect.getABIEncodedTransactionData(
|
||||
new BigNumber(1),
|
||||
ethUtil.bufferToHex(ethUtil.sha3(0)),
|
||||
);
|
||||
|
||||
// Ensure that the correct hash was returned from the cache.
|
||||
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(
|
||||
ethUtil.bufferToHex(ethUtil.sha3(hexSlice(hashData, 4))),
|
||||
);
|
||||
});
|
||||
|
||||
it('should return the null hash when counter != 0', async () => {
|
||||
// Update "counter" to "1", which will cause all calls to return the null hash.
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
|
||||
// Ensure that the cache returns the correct value.
|
||||
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(
|
||||
ethUtil.bufferToHex(ethUtil.sha3('0x')),
|
||||
);
|
||||
});
|
||||
|
||||
it('should return the cached hash', async () => {
|
||||
// Get the calldata for the function call, which includes the abi-encoded data to hash.
|
||||
const hashData = exampleContract.hashSideEffect.getABIEncodedTransactionData(
|
||||
new BigNumber(1),
|
||||
ethUtil.bufferToHex(ethUtil.sha3(0)),
|
||||
);
|
||||
const hash = ethUtil.bufferToHex(ethUtil.sha3(hexSlice(hashData, 4)));
|
||||
|
||||
// Ensure that the cache returns the correct value.
|
||||
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(hash);
|
||||
|
||||
// Update "counter" to "1", which will cause all calls to return the null hash.
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
|
||||
// The cache should return the same value as the first call to `callAsync` since a value was cached.
|
||||
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(hash);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('flush', () => {
|
||||
describe('uint => boolean', () => {
|
||||
let cache: GetterCache;
|
||||
|
||||
beforeEach(async () => {
|
||||
cache = new GetterCache(exampleContract.equalsSideEffect);
|
||||
});
|
||||
|
||||
it('should return false when the cache was flushed && "possiblyZero" == 0 && "counter" != 0', async () => {
|
||||
// Cache a "true" value when "possiblyZero" == 0 && "counter" == 0
|
||||
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
|
||||
|
||||
// Update "counter" to "1", which will cause all calls of "isZeroOrFalse" to return "false".
|
||||
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
|
||||
|
||||
// Flush the entire cache.
|
||||
cache.flush();
|
||||
|
||||
// This should return "false" because the value was flushed.
|
||||
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.false();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,84 +0,0 @@
|
||||
import { ContractGetterFunction } from './function_assertions';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export class GetterCache<TCallArgs extends any[]> {
|
||||
// The getter function whose values will be cached.
|
||||
public getter: ContractGetterFunction<TCallArgs>;
|
||||
|
||||
// The cache that will be used to store values. This has to use a "string" for indexing
|
||||
// because the "Map" datastructure uses reference equality when the keys are objects,
|
||||
// which was unsuitable for our purposes.
|
||||
private cache: {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
constructor(getter: ContractGetterFunction<TCallArgs>) {
|
||||
this.getter = getter;
|
||||
this.cache = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the contract getter and caches the result if there is not a cached value. Otherwise,
|
||||
* this returns the cached value.
|
||||
* @param ...args A variadic list of args to use when calling "callAsync". Due
|
||||
* to the fact that we need to serialize the arguments to "callAsync" these
|
||||
* arguments must be valid arguments to "getABIEncodedTransactionData".
|
||||
* @return Either a cached value or the queried value.
|
||||
*/
|
||||
public async callAsync(...args: TCallArgs): Promise<any> {
|
||||
const key = this.getter.getABIEncodedTransactionData(...args);
|
||||
const cachedResult = this.cache[key];
|
||||
|
||||
if (cachedResult !== undefined) {
|
||||
return cachedResult;
|
||||
} else {
|
||||
const result = await this.getter.callAsync(...args);
|
||||
this.cache[key] = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the entire cache so that future calls to "callAsync" call the contract getter.
|
||||
*/
|
||||
public flush(): void {
|
||||
this.cache = {};
|
||||
}
|
||||
}
|
||||
|
||||
export interface GetterCacheSet {
|
||||
[getter: string]: GetterCache<any[]>;
|
||||
}
|
||||
|
||||
export class GetterCacheCollection {
|
||||
// A dictionary of getter cache's that allow the user of the collection to reference
|
||||
// the getter functions by name.
|
||||
public getters: GetterCacheSet;
|
||||
|
||||
/**
|
||||
* Constructs a getter collection with pre-seeded getter names and getters.
|
||||
* @param getterNames The names of the getter functions to register.
|
||||
* @param getters The getter functions to register.
|
||||
*/
|
||||
constructor(getters: GetterCacheSet) {
|
||||
this.getters = getters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new getter in the collection.
|
||||
* @param getterName The name of the contract getter function.
|
||||
* @param getter The actual contract getter function.
|
||||
*/
|
||||
public registerGetter(getterName: string, getter: ContractGetterFunction<any[]>): void {
|
||||
this.getters[getterName] = new GetterCache(getter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes all of the registered caches.
|
||||
*/
|
||||
public flushAll(): void {
|
||||
for (const getter of Object.keys(this.getters)) {
|
||||
this.getters[getter].flush();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,13 @@
|
||||
import { PromiseWithTransactionHash } from '@0x/base-contract';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
|
||||
export interface ContractGetterFunction<TCallArgs extends any[]> {
|
||||
callAsync: (...args: TCallArgs) => Promise<any>;
|
||||
getABIEncodedTransactionData: (...args: TCallArgs) => string;
|
||||
export interface ContractGetterFunction {
|
||||
callAsync: (...args: any[]) => Promise<any>;
|
||||
getABIEncodedTransactionData: (...args: any[]) => string;
|
||||
}
|
||||
|
||||
export interface ContractWrapperFunction<TAwaitArgs extends any[], TCallArgs extends any[]>
|
||||
extends ContractGetterFunction<TCallArgs> {
|
||||
awaitTransactionSuccessAsync?: (
|
||||
...args: TAwaitArgs
|
||||
) => PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>;
|
||||
export interface ContractWrapperFunction extends ContractGetterFunction {
|
||||
awaitTransactionSuccessAsync?: (...args: any[]) => PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>;
|
||||
}
|
||||
|
||||
export interface Condition {
|
||||
@ -18,14 +15,14 @@ export interface Condition {
|
||||
after: (beforeInfo: any, result: Result, ...args: any[]) => Promise<any>;
|
||||
}
|
||||
|
||||
export class FunctionAssertion<TAwaitArgs extends any[], TCallArgs extends any[]> {
|
||||
export class FunctionAssertion {
|
||||
// A before and an after assertion that will be called around the wrapper function.
|
||||
public condition: Condition;
|
||||
|
||||
// The wrapper function that will be wrapped in assertions.
|
||||
public wrapperFunction: ContractWrapperFunction<TAwaitArgs, TCallArgs>;
|
||||
public wrapperFunction: ContractWrapperFunction;
|
||||
|
||||
constructor(wrapperFunction: ContractWrapperFunction<TAwaitArgs, TCallArgs>, condition: Condition) {
|
||||
constructor(wrapperFunction: ContractWrapperFunction, condition: Condition) {
|
||||
this.condition = condition;
|
||||
this.wrapperFunction = wrapperFunction;
|
||||
}
|
||||
@ -34,7 +31,7 @@ export class FunctionAssertion<TAwaitArgs extends any[], TCallArgs extends any[]
|
||||
* Runs the wrapped function and fails if the before or after assertions fail.
|
||||
* @param ...args The args to the contract wrapper function.
|
||||
*/
|
||||
public async runAsync(args: TAwaitArgs & TCallArgs): Promise<{ beforeInfo: any; afterInfo: any }> {
|
||||
public async runAsync(...args: any[]): Promise<{ beforeInfo: any; afterInfo: any }> {
|
||||
// Call the before condition.
|
||||
const beforeInfo = await this.condition.before(...args);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user