Loading
test(bifrost): keysign byte-parity and gas-unit contract tests with THORNode
Why
test-simulation was the only CI job to catch two bugs in the contract between THORNode and bifrost. Each side's unit tests used its own hand-picked values or static fixtures, so neither side could see the mismatch:
- !4342: a bot commit dropped
InboundFinalizedfrom bifrost'sTxArrayItem. THORNode signs the raw keysign JSON, and bifrost re-marshals what it reads before verifying. The field was silently lost, every keysign failed with "bad signature", and outbounds on every chain stalled. - !3925 (merged): a rebase kept THORNode's switch to per-chain gas units but dropped bifrost's half. EVM outbounds aborted with "max gas exceeded" on every retry, and GAIA MaxGas was 100× too high.
What
bifrost/thorclient/keysign_parity_test.go
- Fills every field of THORNode's
TxOutby reflection, so new fields are covered automatically. - Signs and marshals it the way
queryKeysigndoes, then runs bifrost's realGetKeysign, including signature verification. - Also zeroes each field in turn, to catch
omitemptymismatches.
gas_unit_contract_test.go in evm, ethereum, gaia, xrp, utxo, monero and tron
- Starts from a native gas price and takes the rate the scanner would post.
- Runs that rate through THORNode's real
GetGasDetails, then through the client's real outbound build. - Asserts the outbound is not aborted and that the effective price is about the native price.
- Covers AVAX, BSC, BASE, POL, ETH, GAIA, NOBLE, XRP, BTC, LTC, BCH, DOGE, XMR and TRON. ZEC gets a MaxGas check only. SOL is not applicable: it never reads GasRate or MaxGas.
bifrost/pkg/chainclients/shared/gascontract
- A small helper, imported only by tests, that runs THORNode's gas manager with a stub keeper.
- go.mod and go.sum are unchanged.
Mutation checks
Each mutation below was applied and then reverted.
| Mutation | Result |
|---|---|
Add InboundFinalized to THORNode's TxOutItem only (the !4342 state) |
keysign.tx_array[0].inbound_finalized: signed by THORNode but dropped by bifrost; GetKeysign fails with bad signature |
Delete CloutSpent from bifrost's TxArrayItem |
Fails |
Remove omitempty from bifrost's memo |
Fails |
| EVM scanner posting in the old 1e8 units | 7 of 8 EVM cases fail. The 8th, BSC at 1 gwei, happens to round to the same rate. |
| EVM client converting with ×1e10 | All 8 fail |
| Same two mutations on ETH | Fail |
| Drop GAIA's conversion | Fails with the 100× MaxGas symptom |
Noticed on develop, not fixed here
- BASE outbound gas limit.
buildOutboundTxsubtractsExtraL1GasFeefrom MaxGas. On BASE that can go negative, andbig.Int.Uint64()then returns a huge gas limit instead of aborting. Default config can't hit this today: the minimum MaxGas is 1500, against a 700 L1 fee. - GAIA/NOBLE fee posting.
updateGasFeescomparesfeeDelta.LTE(resolution)against alastFeethat starts at zero. A first fee equal togas_price_resolutionis never posted, so NOBLE at its 100,000 uusdc floor never posts from a fresh scanner. EVM guards this withlastReported != 0. - Keysign JSON tags differ between the two sides.
chain,to_addressandheightdisagree onomitempty. This is harmless today, and the test documents it. - DOGE fee rounding. DOGE rounds up a full 500,000 sats/vB step. This is a config choice, not a units bug.
Testing
go test -tags=mocknet ./bifrost/thorclient/ -run TestPackage -check.f KeysignParitySuite: 3 tests, 0.16 s.go test -tags=mocknet ./bifrost/pkg/chainclients/{evm,ethereum,gaia,xrp,utxo,tron}/ -run 'TestPackage|TestEVMPackage|TestETHPackage' -check.f GasUnitContract: 0.01–0.61 s each.go test -tags=mocknet ./bifrost/pkg/chainclients/monero/ -run '^TestGasUnitContract$'- Also passing:
- the full test suites of every touched package;
-race;- the
mainnettag for utxo and monero; - golangci-lint v1.63.4 with the CI config.