Scalus node emulator#249
Conversation
Implements the Provider interface backed by the Scalus Cardano emulator, enabling local ledger validation for transaction building and submission.
| @@ -0,0 +1,69 @@ | |||
| import "@evolution-sdk/scalus-emulator" | |||
There was a problem hiding this comment.
this whole file is a test util, and I don't insist on it existing in this form
There was a problem hiding this comment.
Thanks, agreed. A small helper avoids duplicating the NodeEmulator setup across these tests, but I am fine reshaping or moving it if we want a more general test utility.
| } | ||
|
|
||
| /** Default protocol parameters matching Cardano mainnet. */ | ||
| const DEFAULT_PROTOCOL_PARAMETERS: ProtocolParameters = { |
There was a problem hiding this comment.
if there's a util that does this better -- i'd really prefer to use it, maybe you can point it out
There was a problem hiding this comment.
I checked and do not see an exported utility for this. The closest is the private buildCostModels helper in Evaluation.ts, so I think we should extract shared protocol and cost-model defaults into evolution core instead of duplicating them here.
Posted without authorization — removed by request.
hadelive
left a comment
There was a problem hiding this comment.
Thank you for adding the Scalus-backed node emulator provider and the related transaction builder coverage. I reviewed the current PR head (caa932274b403bc1b9fee948084991bc174357c9) and I believe this needs changes before it is ready to merge.
The new @evolution-sdk/scalus-emulator package does not currently build. Running pnpm --filter @evolution-sdk/scalus-emulator build fails in packages/scalus-emulator/src/index.ts because NodeEmulatorConfig exposes ReadonlyArray values, while Scalus.EmulatorInitialState expects mutable arrays for stakeRegistrations, poolRegistrations, drepRegistrations, and datums. Please either copy these values into mutable arrays before constructing the Scalus state, or align the public config types with the Scalus API.
The new node-emulator test suite is also not green. Running pnpm --filter @evolution-sdk/devnet test -- NodeEmulator fails in packages/evolution-devnet/test/TxBuilder.Pool.NodeEmulator.test.ts for the retirePool case. The emulator rejects the retirement transaction with Pool certificate validation failed ... not registered, even though the test submits a pool registration first. This should be fixed or the test should be adjusted so the suite reliably validates the intended behavior.
There are also a few packaging and runtime concerns to address before publishing this package:
packages/scalus-emulator/package.jsonexports./src/index.tsand does not define apublishConfigoverride to point consumers atdist, unlike the existing packages. This would publish runtime exports that resolve to TypeScript source.- The same package declares
"sideEffects": [], butpackages/scalus-emulator/src/index.tsrelies on import-time registration viaregisterNodeEmulatorProviderFactory. Bundlers may removeimport "@evolution-sdk/scalus-emulator", which would leave the provider factory unregistered. packages/evolution/package.jsonadds an optional peer dependency back to@evolution-sdk/scalus-emulator, while the emulator package peer-depends on@evolution-sdk/evolution. This introduces a workspace dependency cycle warning during install, and core does not appear to need a peer dependency on the emulator package.
Finally, ScalusEmulatorProvider.evaluateTx appears to ignore caller-supplied cost models from protocolParameters and recreates the Scalus slot config with hard-coded zeroSlot = 0 and slotLength = 1000. That can make evaluation disagree with submission for custom protocol parameters or slot configurations.
Verification performed:
pnpm --filter @evolution-sdk/evolution type-checkpassed.pnpm --filter @evolution-sdk/scalus-uplc type-checkpassed.pnpm --filter @evolution-sdk/devnet type-checkpassed.pnpm --filter @evolution-sdk/scalus-emulator buildfailed as described above.pnpm --filter @evolution-sdk/devnet test -- NodeEmulatorfailed as described above.
Add StakePoolCertificatesMutator (Shelley/Conway POOL state transition): pool registration now lands in pstate.stakePools with its deposit, re-registration goes to futureStakePoolParams and cancels a pending retirement, and retirement is recorded in pstate.retiring. Previously pool certificates were validated but never applied, so a registered pool could not be retired in the Emulator. SlotConfig gains epochLength/zeroEpoch fields and epochOf/firstSlotOfEpoch (mainnet zeroEpoch=208, preprod=4, preview 1-day epochs). StakePoolCertificatesValidator now derives the current epoch from the slot via SlotConfig instead of treating the slot number as an epoch. JS/npm API: Emulator.getSlot(), SlotConfig epoch params in scalus.d.ts, and EmulatorInitialState fields relaxed to ReadonlyArray. Enables pool register/retire flows in the Emulator (needed by the Evolution SDK scalus-emulator provider, IntersectMBO/evolution-sdk#249).
Add VotingCertificatesMutator applying DRep certificates to VotingState: RegDRepCert inserts a DRepState with the deposit (validating it against dRepDeposit), UnregDRepCert removes it (validating the refund against the paid deposit), UpdateDRepCert refreshes the anchor and expiry. Certificates are applied sequentially against the evolving state, like the CERTS rule in cardano-ledger. Committee certificates are accepted but not tracked. Previously DRep registrations submitted via transactions never landed in vstate.dreps, so a subsequent deregistration failed value conservation: the deposit refund lookup found nothing. Found by running the Evolution SDK node-emulator test suite (deregisterDRep) against a local scalus build (IntersectMBO/evolution-sdk#249).
This PR introduces the Scalus node emulator as one of the
Providerimplementations, allowing to write the code against the in-memory Emulator as if it was a real node.It also migrates some of the tests to the scalus emulator, making it drastically faster (180s vs ±3s)
Note on vendored scalus
This PR depends on Scalus features not yet published to npm (
Emulator.withState,getDelegation,getDatum,hasTx). Thevendor/scalus/directory contains a local build of scalus 0.15.0 so reviewers canpnpm install && pnpm testwithout any local setup. The pnpm override in root package.json points to ./vendor/scalus. This will be removed once scalus publishes the new version.