Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions experiments/interoperability/traffic-rewards/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ reward that the network computes from them.
`appRewardCouponThreshold` far below its 0.5 USD default, because the reward of
a run this small stays under that default and a round below the threshold mints
no coupon. LocalNet has one SV and a voting threshold of 1, so the vote of the
requester carries.
requester carries. Each open round stores the reward configuration of the
moment it opened, and the SV mints no coupon for a round that opened under
the old one, so the harness then waits until every open round carries the
new configuration. Splice keeps three rounds open at once, so that wait is
about three rounds.
3. The app-provider settles three USD transfers as the settlement executor. These
settlements are the traffic, and the harness records the ledger record time of
each settle transaction. On the third batch a party that the settlement does
Expand Down Expand Up @@ -90,7 +94,7 @@ The gate reads the variables below.
| Variable | Purpose |
|---|---|
| `OZ_LOCALNET_TICK_DURATION` | Length of a tick, which is half a mining round |
| `OZ_REWARD_TIMEOUT_S` | Seconds to wait for the closed round and the coupon |
| `OZ_REWARD_TIMEOUT_S` | Seconds to wait for the open rounds to carry the reward configuration, the closed round, and the coupon |
| `OZ_TRAFFIC_TIMEOUT_S` | Seconds to wait for validator traffic and for a round to open |
| `OZ_LEDGER_LOG_DIR` | Move the logs and the evidence of the run |
| `OZ_VALIDATOR_API_URL`, `OZ_SV_API_URL`, `OZ_SCAN_API_URL` | Splice service endpoints |
Expand Down
32 changes: 28 additions & 4 deletions experiments/interoperability/traffic-rewards/harness.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
// OZ_LOCALNET_AUTH_AUDIENCE audience that the Splice apps accept
// OZ_WALLET_ADMIN_USER wallet admin user of the app-provider validator
// OZ_SV_USER wallet admin user of the SV
// OZ_REWARD_TIMEOUT_S seconds to wait for the round and the coupon
// OZ_REWARD_TIMEOUT_S seconds to wait for the rounds and the coupon
// OZ_TRAFFIC_TIMEOUT_S seconds to wait for validator traffic and a round
// OZ_EVIDENCE_FILE file for the JSON evidence of the run

Expand Down Expand Up @@ -515,7 +515,7 @@ async function enableTrafficBasedRewards() {
const base = dso.amulet_rules.contract.payload.configSchedule.initialValue
if (base.rewardConfig?.mintingVersion === 'RewardVersion_TrafficBasedAppRewards') {
log('the network already runs traffic-based app rewards')
return
return waitForOpenRoundsUnderTrafficRewards()
}

assertEq('the SV voting threshold is 1', Number(dso.voting_threshold), 1)
Expand All @@ -537,6 +537,28 @@ async function enableTrafficBasedRewards() {
return cfg?.mintingVersion === 'RewardVersion_TrafficBasedAppRewards' ? cfg : null
})
log('the network runs traffic-based app rewards')
return waitForOpenRoundsUnderTrafficRewards()
}

// Each open mining round stores the reward configuration of the moment it
// opened, and the SV processes a round by that stored configuration: a round
// that opened before the vote goes through the dry-run triggers, which compute
// the allowances but mint no coupon. Splice keeps three rounds open at once, so
// the settlements wait until every open round carries the traffic-based
// configuration. The wait returns the numbers of those rounds.
async function waitForOpenRoundsUnderTrafficRewards() {
const rounds = await waitFor('every open mining round to carry the traffic-based reward configuration', async () => {
const res = await scanApi('POST', '/v0/open-and-issuing-mining-rounds', {
cached_open_mining_round_contract_ids: [],
cached_issuing_round_contract_ids: [],
})
const open = Object.values(res.open_mining_rounds ?? {}).map((r) => (r.contract ?? r).payload)
const stale = open.filter((p) => p.rewardConfig?.mintingVersion !== 'RewardVersion_TrafficBasedAppRewards')
if (open.length === 0 || stale.length > 0) return null
return open.map((p) => Number(p.round.number)).sort((a, b) => a - b)
})
log(`open rounds ${rounds.join(', ')} carry the traffic-based reward configuration`)
return rounds
}

const latestRound = async () => {
Expand Down Expand Up @@ -650,8 +672,9 @@ async function main() {
const provider = await selfFeature()
log(`app-provider party: ${provider}`)

// Step 2: the network switches to traffic-based app rewards.
await enableTrafficBasedRewards()
// Step 2: the network switches to traffic-based app rewards, and every open
// round carries that configuration.
const openRounds = await enableTrafficBasedRewards()

// Step 3: the settlement parties. The app-provider executes every settlement,
// so the admin user that this client submits as needs `CanActAs` for the
Expand Down Expand Up @@ -748,6 +771,7 @@ async function main() {
{
runId: RUN_ID,
provider,
openRoundsUnderRewardConfig: openRounds,
settlements: activity.settlements,
settledVolumeUsd: activity.settledVolume,
settleRound,
Expand Down
5 changes: 3 additions & 2 deletions scripts/localnet-cip0104-traffic-rewards.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
# one minute long. The LocalNet default of 10 minutes gives a 20 minute round, and
# the reward needs a closed round.
#
# The run waits for the network: the round must close, Scan must compute its
# per-round totals, and the SV must confirm them before it mints the coupon.
# The run waits for the network: the open rounds must carry the new reward
# configuration, the round must close, Scan must compute its per-round totals,
# and the SV must confirm them before it mints the coupon.
# Together with the image pull of the containers, that makes this an evidence
# gate for a schedule and not a pull-request gate.
#
Expand Down
Loading