Use seeded rng for simulations
This commit is contained in:
parent
6b0f3570b9
commit
d11cdcd5d2
@ -69,6 +69,7 @@
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
@ -78,6 +79,7 @@
|
||||
"mocha": "^6.2.0",
|
||||
"nock": "^10.0.6",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"seedrandom": "^3.0.5",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { constants, OrderFactory } from '@0x/contracts-test-utils';
|
||||
import { Order, SignedOrder } from '@0x/types';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AssertionResult } from '../assertions/function_assertion';
|
||||
import { validJoinStakingPoolAssertion } from '../assertions/joinStakingPool';
|
||||
import { Pseudorandom } from '../pseudorandom';
|
||||
|
||||
import { Actor, ActorConfig, Constructor } from './base';
|
||||
|
||||
@ -88,7 +88,7 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validJoinStakingPoolAssertion(this.actor.deployment);
|
||||
while (true) {
|
||||
const poolId = _.sample(Object.keys(stakingPools));
|
||||
const poolId = Pseudorandom.sample(Object.keys(stakingPools));
|
||||
if (poolId === undefined) {
|
||||
yield undefined;
|
||||
} else {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { constants, StakingPoolById } from '@0x/contracts-staking';
|
||||
import { getRandomInteger } from '@0x/contracts-test-utils';
|
||||
import '@azure/core-asynciterator-polyfill';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
@ -7,6 +6,7 @@ import * as _ from 'lodash';
|
||||
import { validCreateStakingPoolAssertion } from '../assertions/createStakingPool';
|
||||
import { validDecreaseStakingPoolOperatorShareAssertion } from '../assertions/decreaseStakingPoolOperatorShare';
|
||||
import { AssertionResult } from '../assertions/function_assertion';
|
||||
import { Pseudorandom } from '../pseudorandom';
|
||||
|
||||
import { Actor, Constructor } from './base';
|
||||
|
||||
@ -83,7 +83,7 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools);
|
||||
while (true) {
|
||||
const operatorShare = getRandomInteger(0, constants.PPM).toNumber();
|
||||
const operatorShare = Pseudorandom.integer(constants.PPM).toNumber();
|
||||
yield assertion.executeAsync([operatorShare, false], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
@ -92,11 +92,11 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validDecreaseStakingPoolOperatorShareAssertion(this.actor.deployment, stakingPools);
|
||||
while (true) {
|
||||
const poolId = _.sample(this._getOperatorPoolIds(stakingPools));
|
||||
const poolId = Pseudorandom.sample(this._getOperatorPoolIds(stakingPools));
|
||||
if (poolId === undefined) {
|
||||
yield undefined;
|
||||
} else {
|
||||
const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare).toNumber();
|
||||
const operatorShare = Pseudorandom.integer(stakingPools[poolId].operatorShare).toNumber();
|
||||
yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { OwnerStakeByStatus, StakeInfo, StakeStatus, StoredBalance } from '@0x/contracts-staking';
|
||||
import { getRandomInteger } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import '@azure/core-asynciterator-polyfill';
|
||||
import * as _ from 'lodash';
|
||||
@ -8,6 +7,7 @@ import { AssertionResult } from '../assertions/function_assertion';
|
||||
import { validMoveStakeAssertion } from '../assertions/moveStake';
|
||||
import { validStakeAssertion } from '../assertions/stake';
|
||||
import { validUnstakeAssertion } from '../assertions/unstake';
|
||||
import { Pseudorandom } from '../pseudorandom';
|
||||
|
||||
import { Actor, Constructor } from './base';
|
||||
|
||||
@ -75,7 +75,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
while (true) {
|
||||
await balanceStore.updateErc20BalancesAsync();
|
||||
const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address];
|
||||
const amount = getRandomInteger(0, zrxBalance);
|
||||
const amount = Pseudorandom.integer(zrxBalance);
|
||||
yield assertion.executeAsync([amount], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
@ -94,7 +94,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
undelegatedStake.currentEpochBalance,
|
||||
undelegatedStake.nextEpochBalance,
|
||||
);
|
||||
const amount = getRandomInteger(0, withdrawableStake);
|
||||
const amount = Pseudorandom.integer(withdrawableStake);
|
||||
yield assertion.executeAsync([amount], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
@ -104,25 +104,27 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
const assertion = validMoveStakeAssertion(deployment, globalStake, this.stake, stakingPools);
|
||||
|
||||
while (true) {
|
||||
const fromPoolId = _.sample(Object.keys(_.omit(this.stake[StakeStatus.Delegated], ['total'])));
|
||||
const fromPoolId = Pseudorandom.sample(
|
||||
Object.keys(_.omit(this.stake[StakeStatus.Delegated], ['total'])),
|
||||
);
|
||||
const fromStatus =
|
||||
fromPoolId === undefined
|
||||
? StakeStatus.Undelegated
|
||||
: (_.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||
: (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||
const from = new StakeInfo(fromStatus, fromPoolId);
|
||||
|
||||
const toPoolId = _.sample(Object.keys(stakingPools));
|
||||
const toPoolId = Pseudorandom.sample(Object.keys(stakingPools));
|
||||
const toStatus =
|
||||
toPoolId === undefined
|
||||
? StakeStatus.Undelegated
|
||||
: (_.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||
: (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||
const to = new StakeInfo(toStatus, toPoolId);
|
||||
|
||||
const moveableStake =
|
||||
from.status === StakeStatus.Undelegated
|
||||
? this.stake[StakeStatus.Undelegated].nextEpochBalance
|
||||
: this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance;
|
||||
const amount = getRandomInteger(0, moveableStake);
|
||||
const amount = Pseudorandom.integer(moveableStake);
|
||||
|
||||
yield assertion.executeAsync([from, to, amount], { from: this.actor.address });
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { constants, getRandomInteger } from '@0x/contracts-test-utils';
|
||||
import { constants } from '@0x/contracts-test-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { validFillOrderCompleteFillAssertion } from '../assertions/fillOrder';
|
||||
import { AssertionResult } from '../assertions/function_assertion';
|
||||
import { DeploymentManager } from '../deployment_manager';
|
||||
import { Pseudorandom } from '../pseudorandom';
|
||||
|
||||
import { Actor, Constructor } from './base';
|
||||
|
||||
@ -65,7 +65,7 @@ export function TakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
||||
const { marketMakers } = this.actor.simulationEnvironment!;
|
||||
const assertion = validFillOrderCompleteFillAssertion(this.actor.deployment);
|
||||
while (true) {
|
||||
const maker = _.sample(marketMakers);
|
||||
const maker = Pseudorandom.sample(marketMakers);
|
||||
if (maker === undefined) {
|
||||
yield undefined;
|
||||
} else {
|
||||
@ -82,8 +82,8 @@ export function TakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
||||
]);
|
||||
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: getRandomInteger(constants.ZERO_AMOUNT, constants.INITIAL_ERC20_BALANCE),
|
||||
takerAssetAmount: getRandomInteger(constants.ZERO_AMOUNT, constants.INITIAL_ERC20_BALANCE),
|
||||
makerAssetAmount: Pseudorandom.integer(constants.INITIAL_ERC20_BALANCE),
|
||||
takerAssetAmount: Pseudorandom.integer(constants.INITIAL_ERC20_BALANCE),
|
||||
});
|
||||
yield assertion.executeAsync([order, order.takerAssetAmount, order.signature], {
|
||||
from: this.actor.address,
|
||||
|
39
contracts/integrations/test/framework/pseudorandom.ts
Normal file
39
contracts/integrations/test/framework/pseudorandom.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Numberish } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as seedrandom from 'seedrandom';
|
||||
|
||||
class PRNGWrapper {
|
||||
public readonly seed = process.env.UUID || Math.random().toString();
|
||||
private readonly _rng = seedrandom(this.seed);
|
||||
|
||||
/*
|
||||
* Pseudorandom version of _.sample. Picks an element of the given array with uniform probability.
|
||||
* Return undefined if the array is empty.
|
||||
*/
|
||||
public sample<T>(arr: T[]): T | undefined {
|
||||
if (arr.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const index = Math.abs(this._rng.int32()) % arr.length;
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
// tslint:disable:unified-signatures
|
||||
/*
|
||||
* Pseudorandom version of getRandomPortion/getRandomInteger. If two arguments are provided,
|
||||
* treats those arguments as the min and max (inclusive) of the desired range. If only one
|
||||
* argument is provided, picks an integer between 0 and the argument.
|
||||
*/
|
||||
public integer(max: Numberish): BigNumber;
|
||||
public integer(min: Numberish, max: Numberish): BigNumber;
|
||||
public integer(a: Numberish, b?: Numberish): BigNumber {
|
||||
if (b === undefined) {
|
||||
return new BigNumber(this._rng()).times(a).integerValue(BigNumber.ROUND_HALF_UP);
|
||||
} else {
|
||||
const range = new BigNumber(b).minus(a);
|
||||
return this.integer(range).plus(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Pseudorandom = new PRNGWrapper();
|
@ -1,11 +1,11 @@
|
||||
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { Actor } from '../framework/actors/base';
|
||||
import { PoolOperator } from '../framework/actors/pool_operator';
|
||||
import { AssertionResult } from '../framework/assertions/function_assertion';
|
||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||
import { DeploymentManager } from '../framework/deployment_manager';
|
||||
import { Pseudorandom } from '../framework/pseudorandom';
|
||||
import { Simulation, SimulationEnvironment } from '../framework/simulation';
|
||||
|
||||
export class PoolManagementSimulation extends Simulation {
|
||||
@ -22,7 +22,7 @@ export class PoolManagementSimulation extends Simulation {
|
||||
operator.simulationActions.validDecreaseStakingPoolOperatorShare,
|
||||
];
|
||||
while (true) {
|
||||
const action = _.sample(actions);
|
||||
const action = Pseudorandom.sample(actions);
|
||||
yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { blockchainTests, constants } from '@0x/contracts-test-utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { MakerTaker } from '../framework/actors/hybrids';
|
||||
import { Maker } from '../framework/actors/maker';
|
||||
import { AssertionResult } from '../framework/assertions/function_assertion';
|
||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||
import { DeploymentManager } from '../framework/deployment_manager';
|
||||
import { Pseudorandom } from '../framework/pseudorandom';
|
||||
import { Simulation, SimulationEnvironment } from '../framework/simulation';
|
||||
|
||||
import { PoolManagementSimulation } from './pool_management_test';
|
||||
@ -29,7 +29,7 @@ class PoolMembershipSimulation extends Simulation {
|
||||
];
|
||||
|
||||
while (true) {
|
||||
const action = _.sample(actions);
|
||||
const action = Pseudorandom.sample(actions);
|
||||
yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { Actor } from '../framework/actors/base';
|
||||
import { Staker } from '../framework/actors/staker';
|
||||
import { AssertionResult } from '../framework/assertions/function_assertion';
|
||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||
import { DeploymentManager } from '../framework/deployment_manager';
|
||||
import { Pseudorandom } from '../framework/pseudorandom';
|
||||
import { Simulation, SimulationEnvironment } from '../framework/simulation';
|
||||
|
||||
import { PoolManagementSimulation } from './pool_management_test';
|
||||
@ -26,7 +26,7 @@ export class StakeManagementSimulation extends Simulation {
|
||||
poolManagement.generator,
|
||||
];
|
||||
while (true) {
|
||||
const action = _.sample(actions);
|
||||
const action = Pseudorandom.sample(actions);
|
||||
yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ export {
|
||||
export { blockchainTests, BlockchainTestsEnvironment, describe } from './mocha_blockchain';
|
||||
export { chaiSetup, expect } from './chai_setup';
|
||||
export { getCodesizeFromArtifact } from './codesize';
|
||||
export { shortZip } from './lang_utils';
|
||||
export { replaceKeysDeep, shortZip } from './lang_utils';
|
||||
export {
|
||||
assertIntegerRoughlyEquals,
|
||||
assertRoughlyEquals,
|
||||
|
Loading…
x
Reference in New Issue
Block a user