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

Implement Grain Integration functionality in the CLI #3085

Merged
merged 5 commits into from
Sep 8, 2021

Conversation

topocount
Copy link
Member

@topocount topocount commented Jun 1, 2021

Details

This officially hooks up grain integrations into something accessible via the CLI!

I'm open to setting up a CLI flag in addition to allowing the invocation of
grain integrations at the config level as well.

These changes also contain a semantic change for the grain integration
typing. The function exported by a grain integration is now named
GrainIntegrationFunction
The original GrainIntegration type which used to represent the
function is now as follows:

type GrainIntegration = {|
  function: GrainIntegrationFunction,
  name: string
|}

Merge Plan

Merge after #3079

Test Plan

  1. yarn build
  2. from repo root: cd packages/sourcecred/sharness/__snapshots__/test-instance
  3. scdev grain -f
  4. open the new file in the output/grainIntegration and observe 2 lines
    of csv output. The first column containing payout addresses, the
    second column containing payout amounts in BigInt form.

Next Steps

All we need to use it is a way to easily set payout addresses for
participants. This was done by hand in a NodeJS repl in order to
enable the above test case.

@topocount topocount force-pushed the 4-grainIntegration-IO branch 2 times, most recently from 3714583 to 4ca7e28 Compare June 2, 2021 17:23
@topocount topocount requested a review from blueridger June 2, 2021 17:27
Comment on lines 49 to 58
const integrationCurrency = grainInput.currencyDetails.integrationCurrency;
const grainIntegration = grainInput.grainConfig.integration;
if (integrationCurrency && grainIntegration) {
distributions.forEach((distribution) => {
const result = executeGrainIntegration(
ledger,
grainIntegration.function,
distribution,
integrationCurrency,
false
);
if (result.grainIntegrationOutput)
instance.writeGrainIntegrationOutput(
result.grainIntegrationOutput,
distribution
);
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this go in the grain API instead of the grain CLI since it is business logic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. I'll separate the business logic from the I/O

packages/sourcecred/src/api/instance/localInstance.js Outdated Show resolved Hide resolved
@topocount topocount force-pushed the 3-integration-configs branch 2 times, most recently from 39b467e to 2f68004 Compare August 16, 2021 20:30
Comment on lines 57 to 82
if (integrationCurrency && grainIntegration) {
distributions.forEach((distribution) => {
const result = executeGrainIntegration(
ledger,
grainIntegration.function,
distribution,
integrationCurrency,
false
);
results.push(result);
});
}
return results;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems strange for this to return an array of objects that each contain the same ledger, and that in the CLI we encode the assumption that the ledger we passed in is going to be mutated and so we can ignore the ledgers that come out. What about a refactor that looks more like:

Suggested change
if (integrationCurrency && grainIntegration) {
distributions.forEach((distribution) => {
const result = executeGrainIntegration(
ledger,
grainIntegration.function,
distribution,
integrationCurrency,
false
);
results.push(result);
});
}
return results;
}
if (integrationCurrency && grainIntegration) {
let ledgerResult = ledger;
distributions.forEach((distribution) => {
const {ledger: newLedger, output, distributionCredTimestamp} = executeGrainIntegration(
ledger,
grainIntegration.function,
distribution,
integrationCurrency,
false
);
results.push({output, distributionCredTimestamp});
ledgerResult = newLedger;
});
}
return {ledger: ledgerResult, results};
}

Copy link
Member Author

@topocount topocount Aug 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah good catch. We don't ever want to assume it's safe to mutate the same ledger reference across multiple function calls.

Comment on lines 46 to 54
const {distributions, ledger} = await grain(grainInput);

const grainIntegrationResults = executeGrainIntegrationsFromGrainInput(
grainInput,
ledger,
distributions
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to my other comment.

Suggested change
const {distributions, ledger} = await grain(grainInput);
const grainIntegrationResults = executeGrainIntegrationsFromGrainInput(
grainInput,
ledger,
distributions
);
const {distributions, ledger: ledgerBeforeIntegrations} = await grain(grainInput);
const {ledger, results: grainIntegrationResults} = executeGrainIntegrationsFromGrainInput(
grainInput,
ledgerBeforeIntegrations,
distributions
);

Base automatically changed from 3-integration-configs to main August 18, 2021 21:32
This officially hooks up grain integrations into something accessible!
All we need to use it is a way to easily set payout addresses for
participants.

These changes also contain a semantic change for the grain integration
typing. The function exported by a grain integration is now named
`GrainIntegrationFunction`
The original `GrainIntegration` type which used to represent the
function is now as follows:

```js
type GrainIntegration = {|
  function: GrainIntegrationFunction,
  name: string
|}
```

This will allow core to utilize the configured grain integration name
internally, if desired.

Merge Plan: Merge after #3079

Test Plan:
0. `scdev build`
1. from repo root: `cd
   packages/sourcecred/sharness/__snapshots__/test-instance`
2. scdev grain -f
3. open the new file in the output/grainIntegration and observe 2 lines
   of csv output. The first column containing payout addresses, the
   second column containing payout amounts in bigint form.
Business Logic should be agnostic of I/O so it can be utilized
elsewhere. This also lead to a minor API cleanup: Each distribution's
credtimestamp is now included in the integration result, so integration
results now have all the identifying details needed to make them unique.
results.push(result);
});
}
return {ledger: ledgerResult, results};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still seems weird / too heavy that we are returning a bunch of ledgers in results right here. Is there a reason for it, or can we slim down and toss the extra references to garbage collection?

@@ -24,8 +25,15 @@ export type GrainOutput = {|
+ledger: Ledger,
|};

// Similar to GrainIntegrationResult but excludes the ledger
// since only the most recent ledger is relevant
export type GrainIntegrationMultiResult = {|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Why multi? Makes me think it's going to be an array. Not sure I have a better suggestion, I'm all turned around on the namings in this epic lol. timeStampedGrainIntegrationOutput? nah the output is optional... idk. you can keep it.

@@ -47,5 +47,7 @@ export interface Instance extends ReadOnlyInstance {
writeLedger(ledger: Ledger): Promise<void>;

/** writes grain integration output */
writeGrainIntegrationOutput(result: GrainIntegrationResult): Promise<void>;
writeGrainIntegrationOutput(
result: $Shape<GrainIntegrationMultiResult>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why shape? seems unnecessary since the GrainIntegrationOutput attribute is optional already

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to be unopinionated enough to accept the GrainIntegrationResulttype.

@topocount topocount merged commit 435f6c3 into main Sep 8, 2021
@topocount topocount deleted the 4-grainIntegration-IO branch September 8, 2021 17:56
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

Successfully merging this pull request may close these issues.

None yet

2 participants