-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FU transaction feed aggregation (#10489)
closes: #10457 ## Description This implements aggregation of the evidence from oracle operators. Once they all agree it forwards. Some corner cases are deferred for our scheduled error handling work. A testing change was to make the contract's public `makeTestPushInvitation` handle evidence directly instead of putting it through the feed. The feed has its own tests and the purpose of the test invitation is to let a client trigger an advance, not test the feed. A consequence of this is that the existing contract test started advancing, which doesn't work. So I marked the test skip until it does. ### Security Considerations Decentralizes truth of CCTP transaction evidence, split among oracle operators. It waits until all operators have sent evidence of the same transaction. There is more verification to do. (See TODO items) ### Scaling Considerations Small number of new Ecos (one per oracle operator, probably three). The pending transactions are stored in a mapstore until they're resolved. Transactions that are never matched by all operators don't ever get cleaned up. It doesn't keep track of transactions it has published, so this could easily happen if one operator double-reports and the others don't. (If they all double-report, the transaction will repeat… hmmm this needs more work) ### Documentation Considerations To follow up with oracle operators ### Testing Considerations CI ### Upgrade Considerations Not yet deployed but all the exos are meant be upgraded
- Loading branch information
Showing
7 changed files
with
197 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,96 @@ | ||
// Must be first to set up globals | ||
import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; | ||
|
||
import { deeplyFulfilledObject } from '@agoric/internal'; | ||
import { makeHeapZone } from '@agoric/zone'; | ||
import { prepareTransactionFeedKit } from '../../src/exos/transaction-feed.js'; | ||
import { | ||
prepareTransactionFeedKit, | ||
type TransactionFeedKit, | ||
} from '../../src/exos/transaction-feed.js'; | ||
import { MockCctpTxEvidences } from '../fixtures.js'; | ||
|
||
const nullZcf = null as any; | ||
|
||
test('basics', t => { | ||
const makeFeedKit = () => { | ||
const zone = makeHeapZone(); | ||
const kit = prepareTransactionFeedKit(zone, nullZcf); | ||
t.deepEqual(Object.values(kit), []); | ||
const makeKit = prepareTransactionFeedKit(zone, nullZcf); | ||
return makeKit(); | ||
}; | ||
|
||
const makeOperators = (feedKit: TransactionFeedKit) => { | ||
const operators = Object.fromEntries( | ||
['op1', 'op2', 'op3'].map(name => [ | ||
name, | ||
feedKit.creator.initOperator(name), | ||
]), | ||
); | ||
return deeplyFulfilledObject(harden(operators)); | ||
}; | ||
|
||
test('facets', t => { | ||
const kit = makeFeedKit(); | ||
t.deepEqual(Object.keys(kit).sort(), ['creator', 'operatorPowers', 'public']); | ||
}); | ||
|
||
test('status shape', async t => { | ||
const { op1 } = await makeOperators(makeFeedKit()); | ||
|
||
// status shape | ||
t.deepEqual(op1.operator.getStatus(), { | ||
disabled: false, | ||
operatorId: 'op1', | ||
}); | ||
}); | ||
|
||
test('happy aggregation', async t => { | ||
const feedKit = makeFeedKit(); | ||
const evidenceSubscriber = feedKit.public.getEvidenceSubscriber(); | ||
|
||
const { op1, op2, op3 } = await makeOperators(feedKit); | ||
const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); | ||
const results = await Promise.all([ | ||
op1.operator.submitEvidence(evidence), | ||
op2.operator.submitEvidence(evidence), | ||
op3.operator.submitEvidence(evidence), | ||
]); | ||
t.deepEqual(results, [undefined, undefined, undefined]); | ||
|
||
const accepted = await evidenceSubscriber.getUpdateSince(0); | ||
t.deepEqual(accepted, { | ||
value: evidence, | ||
updateCount: 1n, | ||
}); | ||
|
||
// verify that it doesn't publish until three match | ||
await Promise.all([ | ||
// once it publishes, it doesn't remember that it already saw these | ||
op1.operator.submitEvidence(evidence), | ||
op2.operator.submitEvidence(evidence), | ||
// but this time the third is different | ||
op3.operator.submitEvidence(MockCctpTxEvidences.AGORIC_PLUS_DYDX()), | ||
]); | ||
t.like(await evidenceSubscriber.getUpdateSince(0), { | ||
// Update count is still 1 | ||
updateCount: 1n, | ||
}); | ||
await op3.operator.submitEvidence(evidence); | ||
t.like(await evidenceSubscriber.getUpdateSince(0), { | ||
updateCount: 2n, | ||
}); | ||
}); | ||
|
||
// TODO: find a way to get this working | ||
test.skip('forged source', async t => { | ||
const feedKit = makeFeedKit(); | ||
const { op1 } = await makeOperators(feedKit); | ||
const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); | ||
|
||
// op1 is different than the facets object the evidence must come from | ||
t.throws(() => | ||
feedKit.operatorPowers.submitEvidence( | ||
evidence, | ||
// @ts-expect-error XXX Types of property '[GET_INTERFACE_GUARD]' are incompatible. | ||
op1, | ||
), | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.