Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High-level declarative workload classes implementation issues #2

Open
aklenik opened this issue Nov 30, 2021 · 4 comments
Open

High-level declarative workload classes implementation issues #2

aklenik opened this issue Nov 30, 2021 · 4 comments

Comments

@aklenik
Copy link

aklenik commented Nov 30, 2021

  1. The DeclarativeWorkloadModuleBase should just simply extend the WorkloadModuleBase class, which performs most of the initialization. Then the initializeWorkloadModule function can be overridden to perform the extra init step (after calling the super init).
    class DeclarativeWorkloadModuleBase extends WorkloadModuleInterface {
  2. The following lines look "weird", not really the JS way. Simply use this.something = {}; instead

  3. The intention is cleaner and easier to read if you use for(const key of Object.keys(roundArguments)) { ... } to iterate through the keys of an object.
  4. You don't need to save this on the instance level, won't use it outside of this function:
  5. This doesn't enumerate the objects, only the key names (string), whatever those are for array entries. You need for(const contractObject of roundArguments.contracts) {...} (instead of in)
  6. You should pass the entire contract object for the constructor (plus some extra arguments) since you'll need the function selector part later:
    this.contracts[contractObject.name] = new Contract(contractObject, variables, parameters, valueProviderFactory);
    Instead of:
    this.contracts[contract.name] = new Contract(contract.functions);
  7. You don't need these, the Contract just passes them down the hierarchy:
    this.variables = variables;
    this.parameters = parameters;
  8. Instead of this:

    You need to construct an object for each function and store them:
    for (const functionObject of functions) {
        this.functions[functionObject.name] = new ContractFunction(functionObject, variables, parameters, valueProviderFactory);
    }
@aklenik
Copy link
Author

aklenik commented Dec 6, 2021

The above issues are fixed 👍

Additional remarks:

  1. Since the ValueProviderFactory already holds the variables and parameters, there's no need to propagate them along the hierarchy, my bad. So the following lines can drop the variables/parameters arguments:
    this.contracts[contractObject.name] = new Contract(contractObject, this.variables, this.parameters, valueProviderFactory);

    constructor(contract, variables, parameters, valueProviderFactory) {

    this.functions[functionObject.name] = new ContractFunction(functionObject, variables, parameters, valueProviderFactory);

    constructor(functionReference, variables, parameters, valueProviderFactory) {

    this.parameters[parameterObject.name] = new ContractFunctionParameter(parameterObject, variables, parameters, valueProviderFactory);

    constructor(parameterReference, variables, parameters, valueProviderFactory) {
  2. What is parameterList? I guess it's a leftover variable. Also there is a trailing space linting error before this part:
    if(this.parameterList === undefined) {
    throw new Error('Incorrect Value for parmeterList: undefined');
    }
    if(this.parameterList.length < 1) {
    throw new Error('Insufficient length of parameterList');
    }
  3. This should be saved as this.valueProvider, its intention is more clear that way:
    this.parameter = valueProviderFactory.createValueProvider(parameterReference.type, parameterReference.options);
  4. The overridden super function must be called before this line, so the parameters are saved in the base class:

Next tasks

T1. The generateValue call should return the value generated by the underlying value provider:

generateValue() {
return this.parameter;
}
}

T2. The generateCallArguments call should return a value for every parameter of a function (by calling their generateValue function). The new values should be returned in a key-value object style: { param1Name: value1; param2Name: value2; }

generateCallArguments() {
return this.parameters;
}

T3. The DeclarativeWorkloadModuleBase class should have a "selector" variable, that can select a uniformly random contract name from the available contracts (reusing hardwired value provider objects that achieve exactly what we want).

T4. The Contract class should have a "selector" variable, that can select a uniformly random function name from the available functions (reusing hardwired value provider objects that achieve exactly what we want).

@aklenik
Copy link
Author

aklenik commented Dec 14, 2021

Next remarks:

  1. You are missing the new operator from here:
    const valueProviderFactory = ValueProviderFactory(this.variables, this.parameters);
  2. Should also check that the list has at least one element:
  3. Will this give a correct range?
    return this.referenceList[Math.floor(Math.random() * (this.referenceList.length - 1))];

    For a 1 element list: floor([0,1) * 0) = floor(0) = 0 (correct)
    For a 2 elements list: floor([0,1) * 1) = floor([0,1)) = 0 (always the first is selected)
    For a 3 elements list: floor([0,1) * 2) = floor([0,2)) = [0,1] (the last is never selected)
    For a 4 elements list: floor([0,1) * 3) = floor([0,3)) = [0,2] (the last is never selected)
    ... and so on. So the last element is never selected. You need to multiply with only this.referenceList.length
  4. The selectors in the workload module and in the Contract class should be called contractSelector and functionSelector, respectively.
  5. Don't overwrite your ContractFunctionParameter instances here, you will also need them on the next generate call:
    this.parameters[parameterKey] = this.parameters[parameterKey].generateValue();

    Instead, create a new empty object (like callAruments) and add the newly generated values to that.

@aklenik
Copy link
Author

aklenik commented Dec 15, 2021

Issues

  1. generatedValues is a local variable, so don't need the this
    this.generatedValues[parameterKey] = this.parameters[parameterKey].generateValue();
  2. The first call needs to be a super call to the same function of the base class, so it initializes the instance variables:
    async initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext) {
    this.variables = {

    So add this as first line in the function:
    await super.initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext);

Tasks

T1. Randomly select a contract function, and return its generated arguments:

generateCallArguments() {
return this.functions;
/**
* return this.functions[this.selector.generateValue()].generateCallArguments();
*/
}
}

T2. Randomly select a contract and returns its (randomly selected function's) generated arguments:

T3. submitTransaction should call a new submitWithArguments(generatedArguments) function, that can be implemented by derived classes (it should throw an error in the DeclarativeWorkloadModuleBase class). So as for now, we leave the actual "custom args to connector args" transformation to be implemented in derived classes, and we won't automate it for now.

@aklenik
Copy link
Author

aklenik commented Dec 23, 2021

Awesome 👍 The only thing left is to expose the workload module class from the core package, so users can use it for their workload modules as a base class.

Just add a similar export to the end of this file:

module.exports.WorkloadModuleBase = require('./lib/worker/workload/workloadModuleBase');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant