From 985581c336b15d97786759a4c4e8a97b0cd6b0e9 Mon Sep 17 00:00:00 2001 From: Ruslan Shevchenko Date: Wed, 23 Sep 2026 09:56:26 +0300 Subject: [PATCH 1/3] feat(config): begin and end a registry migration with update-config, and read a Config that grew A registry revision (spec rev 5.6, [CFG-10]) is one governance Update that moves Config #9 to the new registry and appends #13, the registry pools are crossing from. update-config now does exactly that. `--migrate-registry-to` writes #9 and takes #13 from the value #9 held, so it cannot be mistyped, and it insists on `--spo-bans-policy` in the same Update, because the ban list moves with the registry. `--end-registry-migration` empties #13 without removing it. A Config longer than the rev-5.5 layout used to be refused by update-config, because re-encoding it would drop the appended field. DeployedConfig now carries appended fields verbatim, and update-config plus the three off-chain readers decode through it. ConfigDatum stays the thirteen-field mirror, because TreasuryMovementValidator decodes it on chain and a fourteenth field would move its pin. New tests evaluate the deployed TM blueprint program, confirm and mint alike, against a Config with #13 appended, both mid-migration and ended: the live validator accepts it, so the migration's Update does not stop treasury movements. --- src/main/scala/binocular/cli/CliApp.scala | 42 ++++- .../cli/commands/BridgeSweepSetup.scala | 4 +- .../cli/commands/UpdateConfigCommand.scala | 147 ++++++++++++++---- .../scala/binocular/server/ProofService.scala | 6 +- .../binocular/watchtower/ConfigTypes.scala | 72 ++++++++- .../binocular/watchtower/PorSweeper.scala | 11 +- .../TreasuryMovementValidatorTest.scala | 51 +++++- .../cli/UpdateConfigCommandTest.scala | 114 ++++++++++++-- 8 files changed, 384 insertions(+), 63 deletions(-) diff --git a/src/main/scala/binocular/cli/CliApp.scala b/src/main/scala/binocular/cli/CliApp.scala index a5e3171..4f32300 100644 --- a/src/main/scala/binocular/cli/CliApp.scala +++ b/src/main/scala/binocular/cli/CliApp.scala @@ -53,6 +53,7 @@ object CliApp { pegInWithdrawHash: Option[String], pegOutWithdrawHash: Option[String], params: binocular.cli.commands.UpdateConfigCommand.ParamEdits, + registry: binocular.cli.commands.UpdateConfigCommand.RegistryEdit, allowUnsafeSchedule: Boolean, dryRun: Boolean ) @@ -358,8 +359,9 @@ object CliApp { Opts.subcommand( "update-config", "Update the deployed Config UTxO in place (governance): the script hashes in " + - "fields 3-6, the ban policy in fields 7-10, and the operational parameters " + - "nested in field 14. Only what you name changes" + "fields 3-6, the ban policy in fields 7-10, the operational parameters " + + "nested in field 14, and a registry migration (fields 9 and 13). Only what you " + + "name changes" ) { val bridgeStatePolicyOpt = Opts .option[String]( @@ -497,6 +499,39 @@ object CliApp { "deployments; the broken constraints are printed either way" ) .orFalse + // spec [CFG-10]: a registry migration moves field 9 and records the registry it + // held in field 13, in one edit — the two mean something only together, and a + // hand-typed field 13 that is not the old field 9 strands every registration. + val migrateRegistryOpt: Opts[UpdateConfigCommand.RegistryEdit] = Opts + .option[String]( + "migrate-registry-to", + help = "Begin a registry migration: config field 9 := this spos_registry " + + "policy (56 hex), field 13 := the one it replaces. Needs " + + "--spo-bans-policy in the same Update" + ) + .mapValidated(arg => + val h = arg.trim + if h.length == 56 && h.forall(c => "0123456789abcdefABCDEF".contains(c)) + then + cats.data.Validated.validNel( + UpdateConfigCommand.RegistryEdit.MigrateTo(ByteString.fromHex(h)) + ) + else + cats.data.Validated.invalidNel( + s"--migrate-registry-to must be a 56-hex-char policy id, got '$arg'" + ) + ) + val endMigrationOpt: Opts[UpdateConfigCommand.RegistryEdit] = Opts + .flag( + "end-registry-migration", + help = "End a registry migration: empty config field 13 once every pool " + + "has crossed. Roster reads go back to checking the current list alone" + ) + .as(UpdateConfigCommand.RegistryEdit.EndMigration) + val registryOpt: Opts[UpdateConfigCommand.RegistryEdit] = + migrateRegistryOpt + .orElse(endMigrationOpt) + .withDefault(UpdateConfigCommand.RegistryEdit.Keep) // Every option is applied in ONE Update tx — a validator migration requires its // dependent fields to flip together, and a params update is one signed act. ( @@ -505,6 +540,7 @@ object CliApp { pegInHashOpt, pegOutHashOpt, paramsOpt, + registryOpt, allowUnsafeScheduleFlag, dryRunFlag ) @@ -795,6 +831,7 @@ object CliApp { pegInHash, pegOutHash, params, + registry, allowUnsafeSchedule, dryRun ) => @@ -804,6 +841,7 @@ object CliApp { pegInHash, pegOutHash, params, + registry, allowUnsafeSchedule, dryRun ) diff --git a/src/main/scala/binocular/cli/commands/BridgeSweepSetup.scala b/src/main/scala/binocular/cli/commands/BridgeSweepSetup.scala index e0d8fa7..8428fa0 100644 --- a/src/main/scala/binocular/cli/commands/BridgeSweepSetup.scala +++ b/src/main/scala/binocular/cli/commands/BridgeSweepSetup.scala @@ -70,8 +70,8 @@ object BridgeSweepSetup { } .toRight(s"no UTxO carrying the config NFT at $configAddress") cfg <- configUtxo.output.inlineDatum - .flatMap(d => Try(d.to[ConfigDatum]).toOption) - .toRight("config datum does not decode as the rev-5.5 ConfigDatum") + .toRight("config UTxO carries no inline datum") + .flatMap(d => DeployedConfig.decode(d).map(_.config)) } yield (configUtxo, cfg) def loadSingletonContext( diff --git a/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala b/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala index 23bc77d..fea3e10 100644 --- a/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala +++ b/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala @@ -10,12 +10,10 @@ import scalus.cardano.node.TransactionStatus import scalus.cardano.onchain.plutus.prelude.{List as PList, Option as SOption} import scalus.cardano.txbuilder.TxBuilder import scalus.uplc.builtin.{ByteString, Data} -import scalus.uplc.builtin.Data.toData import scalus.utils.await import scala.concurrent.ExecutionContext import scala.concurrent.duration.* -import scala.util.Try import scala.util.boundary import boundary.break import cats.syntax.either.* @@ -41,6 +39,12 @@ import cats.syntax.either.* * deliberately, and for all of them at once. It takes effect from the next batch, never * retroactively; the schedule (params[3]) from the next epoch boundary. * + * - optionally begins or ends a REGISTRY MIGRATION (spec [CFG-10]): `--migrate-registry-to` + * moves field 9 (`spos_registry_policy_id`) to the new registry and writes the policy it held + * into field 13 (`previous_spos_registry_policy_id`, appended if the datum predates it) — the + * on-chain statement "pools are crossing from here", which the `Migrate` branch and every + * heimdall read. `--end-registry-migration` empties field 13 once they have. + * * ALL of the above happen in ONE transaction: a validator swap must flip every dependent field in * the same Update that precedes its first use, or readers chase hashes whose UTxOs do not exist. * @@ -49,9 +53,9 @@ import cats.syntax.either.* * non-ADA value are preserved (config.ak enforces this); all other datum fields are carried over * verbatim. * - * The rewrite decodes the typed [[ConfigDatum]] and edits fields by name ([LIB-1]). Because the - * whole datum is re-encoded, a deployed datum whose field count grew past the layout this build - * knows is REFUSED up front: re-encoding it would silently drop the appended fields. + * The rewrite decodes the typed [[ConfigDatum]] and edits fields by name ([LIB-1]). Fields + * appended after the rev-5.5 layout are carried through [[DeployedConfig]] verbatim, so an Update + * never truncates a grown datum. * * The config script is rebuilt from the bridge blueprint parameterized by the bootstrap one-shot * (`bridge.completed-peg-ins-one-shot-ref` — deploy-bridge uses ONE shared one-shot for config, @@ -63,6 +67,7 @@ case class UpdateConfigCommand( pegInWithdrawHash: Option[String] = None, pegOutWithdrawHash: Option[String] = None, params: UpdateConfigCommand.ParamEdits = UpdateConfigCommand.ParamEdits.none, + registry: UpdateConfigCommand.RegistryEdit = UpdateConfigCommand.RegistryEdit.Keep, allowUnsafeSchedule: Boolean = false, dryRun: Boolean = false ) extends Command { @@ -99,12 +104,12 @@ case class UpdateConfigCommand( // With every option now optional, a bare `update-config` would spend and recreate the config // UTxO with an identical datum — a fee for nothing, and a needless spend of the config NFT. if newBridgeStatePolicy.isEmpty && newTmScriptHash.isEmpty && newPegInHash.isEmpty - && newPegOutHash.isEmpty && params.isEmpty + && newPegOutHash.isEmpty && params.isEmpty && registry == UpdateConfigCommand.RegistryEdit.Keep then { Console.error( "Nothing to update. Pass at least one of --bridge-state-policy, --tm-script-hash, " + "--peg-in-withdraw-hash, --peg-out-withdraw-hash, --fee-rate, --per-pegout-fee, " + - "--min-peg-out, --schedule." + "--min-peg-out, --schedule, --migrate-registry-to, --end-registry-migration." ) break(1) } @@ -167,18 +172,25 @@ case class UpdateConfigCommand( Console.error("Config UTxO has no inline datum") break(1) } - val oldConfig = UpdateConfigCommand.decodeDeployed(oldData).valueOr { err => + val deployed = UpdateConfigCommand.decodeDeployed(oldData).valueOr { err => Console.error(err); break(1) } - val newConfig = UpdateConfigCommand.rewrite( - oldConfig, - newBridgeStatePolicy, - newTmScriptHash, - newPegInHash, - newPegOutHash, - params + val oldConfig = deployed.config + val rewritten = deployed.copy(config = + UpdateConfigCommand.rewrite( + oldConfig, + newBridgeStatePolicy, + newTmScriptHash, + newPegInHash, + newPegOutHash, + params + ) ) - val newDatum: Data = newConfig.toData + val updated = UpdateConfigCommand + .applyRegistryEdit(rewritten, registry, banPolicyMoved = params.spoBansPolicyId.nonEmpty) + .valueOr { err => Console.error(err); break(1) } + val newConfig = updated.config + val newDatum: Data = updated.toData val updateAuthPkh = oldConfig.updateAuth match { case SOption.Some(AuthorizationMethod.CardanoSignature(pkh)) => pkh case SOption.Some(other) => @@ -202,6 +214,17 @@ case class UpdateConfigCommand( newTmScriptHash.foreach(h => Console.info("new TM script hash (field 4)", h.toHex)) newPegInHash.foreach(h => Console.info("new peg-in hash (field 5)", h.toHex)) newPegOutHash.foreach(h => Console.info("new peg-out hash (field 6)", h.toHex)) + registry match { + case UpdateConfigCommand.RegistryEdit.MigrateTo(r) => + Console.info( + "registry migration", + s"${oldConfig.sposRegistryPolicyId.toHex} -> ${r.toHex} (field 13 records " + + "the old one until --end-registry-migration)" + ) + case UpdateConfigCommand.RegistryEdit.EndMigration => + Console.info("registry migration", "ended — field 13 emptied") + case UpdateConfigCommand.RegistryEdit.Keep => () + } Console.info("update_auth pkh", updateAuthPkh.toHex) // Every changed field, old -> new. The operational parameters are consensus inputs for // every SPO's TM builder, so an accidental edit is worth seeing before it is signed. @@ -347,29 +370,86 @@ object UpdateConfigCommand { } /** Field count of the rev-5.5 Config datum (spec §Config datum). */ - val ConfigFieldCount = 13 + val ConfigFieldCount: Int = DeployedConfig.TypedFieldCount - /** Decode the deployed Config datum for an UPDATE, refusing any Constr arity other than - * [[ConfigFieldCount]]. Appends are the legal datum evolution and read-only consumers ignore - * unknown trailing fields, but this command re-encodes the WHOLE datum — a - * decode-copy-reencode of a grown datum would silently drop the appended fields, so it is - * refused instead. + /** Decode the deployed Config datum for an UPDATE. + * + * This used to REFUSE any arity but [[ConfigFieldCount]], because it re-encoded the typed + * record and a longer datum would have lost its appended fields. [[DeployedConfig]] carries + * them through verbatim instead, which is what lets this command write rev 5.6's #13 — and + * keep writing every other field after it exists. */ - def decodeDeployed(datum: Data): Either[String, ConfigDatum] = datum match { - case Data.Constr(0, fields) => - val n = fields.asScala.size - if n != ConfigFieldCount then + def decodeDeployed(datum: Data): Either[String, DeployedConfig] = DeployedConfig.decode(datum) + + /** Beginning or ending a registry migration ([CFG-10]). */ + enum RegistryEdit { + case Keep + + /** Field 9 := `newRegistry`, field 13 := the policy field 9 held. */ + case MigrateTo(newRegistry: ByteString) + + /** Field 13 := empty. */ + case EndMigration + } + + /** Apply a [[RegistryEdit]] to a deployed Config. + * + * One edit, not a free-standing "set field 13": the two fields mean something only together. + * Field 13 names the registry the pools are crossing FROM, so it must be exactly what field 9 + * held — a hand-typed value that is not strands every pool in a list nothing reads. And it + * is written in the same Update that moves field 9, or there is a window in which the + * registry has moved and no reader knows where the registrations went. + * + * `banPolicyMoved` must be true for [[RegistryEdit.MigrateTo]]. The three fault verifiers are + * compiled from the registry hash and the ban policy from theirs, so a ban list built for the + * old registry authorizes fault proofs no new node can mint: field 7 moves in the same Update. + */ + def applyRegistryEdit( + deployed: DeployedConfig, + edit: RegistryEdit, + banPolicyMoved: Boolean + ): Either[String, DeployedConfig] = edit match { + case RegistryEdit.Keep => Right(deployed) + case RegistryEdit.MigrateTo(newRegistry) => + val current = deployed.config.sposRegistryPolicyId + if newRegistry.size != 28 then + Left(s"--migrate-registry-to must be a 28-byte policy id, got ${newRegistry.size}") + else if newRegistry == current then + Left( + s"--migrate-registry-to names the registry field 9 already holds (${current.toHex})" + ) + else if deployed.previousSposRegistryPolicyId.nonEmpty then + Left( + "a registry migration is already in progress, from " + + s"${deployed.previousSposRegistryPolicyId.get.toHex} (field 13). End it with " + + "--end-registry-migration once every pool has crossed, then start the next" + ) + else if !banPolicyMoved then Left( - s"config datum has $n fields; this build knows the $ConfigFieldCount-field " + - "rev-5.5 layout. Re-encoding would drop the extra fields — update binocular " + - "instead of forcing the write." + "--migrate-registry-to needs --spo-bans-policy in the same Update: the fault " + + "verifiers are compiled from the registry hash and the ban policy from " + + "theirs, so the ban list for the new registry is a new policy too" + ) + else + Right( + deployed.copy( + config = deployed.config.copy(sposRegistryPolicyId = newRegistry), + appended = withField13(deployed.appended, Data.B(current)) + ) ) + case RegistryEdit.EndMigration => + if deployed.previousSposRegistryPolicyId.isEmpty then + Left("no registry migration is in progress: field 13 is absent or empty") else - Try(datum.to[ConfigDatum]).toOption - .toRight("config datum does not decode as the rev-5.5 ConfigDatum") - case other => Left(s"config datum is not a Constr 0 record: $other") + Right( + deployed.copy(appended = withField13(deployed.appended, Data.B(ByteString.empty))) + ) } + /** `appended` with its first entry — Config #13 — set to `value`, appending it if absent. */ + private def withField13(appended: List[Data], value: Data): List[Data] = + value :: appended.drop(1) + /** `ScheduleParams` field names, in record order — the `--schedule name=value` keys and the * positions inside the doubly-nested Constr at params[3]. */ @@ -400,7 +480,8 @@ object UpdateConfigCommand { "spos_registry_policy_id", "treasury_info_policy_id", "y_federation", - "federation_one_shot" + "federation_one_shot", + "previous_spos_registry_policy_id" ) /** The governed parameter edits (config fields 7-10 and inside field 14). All optional: `None` diff --git a/src/main/scala/binocular/server/ProofService.scala b/src/main/scala/binocular/server/ProofService.scala index dbe6fd0..f7f6dc1 100644 --- a/src/main/scala/binocular/server/ProofService.scala +++ b/src/main/scala/binocular/server/ProofService.scala @@ -6,7 +6,7 @@ import binocular.cli.{CommandHelpers, ValidOracleUtxo} import binocular.cli.commands.BridgeSweepSetup import binocular.oracle.{BitcoinContract, ChainState} import binocular.server.ProofApi.ApiError -import binocular.watchtower.{BridgeState, ConfigDatum, CpoHistorySource, PegInProofBundle, ProviderChainHistory, SweptPegInsProofService, TreasuryMovementValidator} +import binocular.watchtower.{BridgeState, CpoHistorySource, DeployedConfig, PegInProofBundle, ProviderChainHistory, SweptPegInsProofService, TreasuryMovementValidator} import binocular.server.ProofService.{DepositProof, SweptSnapshot} import scalus.cardano.address.{Address, Network} @@ -138,12 +138,12 @@ final class ProofService( code = "config_missing" ) config <- configUtxo.output.inlineDatum - .flatMap(d => Try(d.to[ConfigDatum]).toOption) + .flatMap(d => DeployedConfig.decode(d).toOption.map(_.config)) .toRight( ApiError( 503, "config_malformed", - "the config UTxO's datum does not decode as the rev-5.4 ConfigDatum" + "the config UTxO's datum does not decode as a bridge ConfigDatum" ) ) singletonUtxo <- findByNft( diff --git a/src/main/scala/binocular/watchtower/ConfigTypes.scala b/src/main/scala/binocular/watchtower/ConfigTypes.scala index b71b801..ffd8244 100644 --- a/src/main/scala/binocular/watchtower/ConfigTypes.scala +++ b/src/main/scala/binocular/watchtower/ConfigTypes.scala @@ -90,7 +90,77 @@ object ConfigDatum { } -// Scalus mirror of `config.ak::ConfigParams` — every value with NO on-chain reader, nested as +/** A deployed Config datum: the typed rev-5.5 fields, and whatever the bridge has APPENDED since. + * + * [CFG-5] makes appending the legal way the datum evolves, and the first append is rev 5.6's #13, + * `previous_spos_registry_policy_id` ([CFG-10]), written by the governance Update that moves the + * registry. [[ConfigDatum]] stays the thirteen-field rev-5.5 mirror on purpose: + * `TreasuryMovementValidator` decodes it ON CHAIN, so a fourteenth field there would move that + * validator's pinned hash — a new TM script for a change that does not concern it. Appended fields + * are therefore kept here as raw [[Data]], and every off-chain read and write goes through this + * one type, so none of them depends on how the derived decoder treats a longer record. + * + * Deliberately NOT the [[ConfigDatum]] companion: nothing a compiled validator can reach. + */ +final case class DeployedConfig(config: ConfigDatum, appended: List[Data]) { + + /** The datum as it goes back on chain: the typed fields, then the appended ones verbatim. */ + def toData: Data = DeployedConfig.encode(this) + + /** Config #13 ([CFG-10]): the registry a migration is coming FROM. `None` when the field is + * absent (a datum written before rev 5.6) or empty (no migration in progress) — the two mean + * the same, exactly as heimdall reads them. + */ + def previousSposRegistryPolicyId: Option[ByteString] = appended.headOption.collect { + case Data.B(b) if b.size > 0 => b + } +} + +object DeployedConfig { + + /** Field count of the rev-5.5 layout [[ConfigDatum]] mirrors. */ + val TypedFieldCount = 13 + + /** The typed fields, then the appended ones verbatim. Here rather than in the class, where the + * class's own `toData` would shadow the `ConfigDatum` encoder. + */ + def encode(d: DeployedConfig): Data = { + import scalus.uplc.builtin.Data.toData + d.config.toData match { + case Data.Constr(tag, fields) => + Data.Constr( + tag, + scalus.cardano.onchain.plutus.prelude.List.from(fields.asScala.toList ++ d.appended) + ) + case other => other + } + } + + /** Decode a deployed Config datum of ANY arity from [[TypedFieldCount]] up. */ + def decode(datum: Data): Either[String, DeployedConfig] = datum match { + case Data.Constr(0, fields) => + val all = fields.asScala.toList + if all.size < TypedFieldCount then + Left( + s"config datum has ${all.size} fields; the rev-5.5 layout has $TypedFieldCount " + + "and a Config only ever grows ([CFG-5]) — this is not a bridge Config" + ) + else + val (typed, appended) = all.splitAt(TypedFieldCount) + scala.util + .Try( + Data.Constr(0, scalus.cardano.onchain.plutus.prelude.List.from(typed)) + .to[ConfigDatum] + ) + .toEither + .left + .map(e => s"config datum does not decode as the rev-5.5 ConfigDatum: $e") + .map(DeployedConfig(_, appended)) + case other => Left(s"config datum is not a Constr 0 record: $other") + } +} + +// Scalus mirror of `config.ak::ConfigParams` — every value with NO on-chain reader, nested as// Scalus mirror of `config.ak::ConfigParams` — every value with NO on-chain reader, nested as // ConfigDatum field 1 (spec §Config datum). Positional; keep field order identical to the .ak // record: 0 schedule, 1 fee_rate_sat_per_vb, 2 per_pegout_fee, 3 min_peg_out_fbtc, // 4 base_ban_duration_ms, 5 max_faults_before_permanent, 6 max_validity_window_ms, diff --git a/src/main/scala/binocular/watchtower/PorSweeper.scala b/src/main/scala/binocular/watchtower/PorSweeper.scala index f6cd357..69d9b75 100644 --- a/src/main/scala/binocular/watchtower/PorSweeper.scala +++ b/src/main/scala/binocular/watchtower/PorSweeper.scala @@ -615,10 +615,13 @@ object PorSweeper { def deployedConfig(configUtxo: Utxo): Either[String, ConfigDatum] = configUtxo.output.inlineDatum match { case Some(datum) => - Try(datum.to[ConfigDatum]).toEither.left.map(e => - "config UTxO datum does not decode as a ConfigDatum — the deployed bridge is " + - s"not the rev-5.5 twelve-field shape this binary reads: ${e.getMessage}" - ) + // Through [[DeployedConfig]], so a Config that has grown an appended field — rev + // 5.6's #13 is the first — still reads as the bridge it is. + DeployedConfig + .decode(datum) + .map(_.config) + .left + .map(e => s"config UTxO datum does not decode as a ConfigDatum: $e") case None => Left("config UTxO carries no inline datum") } diff --git a/src/test/scala/binocular/TreasuryMovementValidatorTest.scala b/src/test/scala/binocular/TreasuryMovementValidatorTest.scala index bacfd8b..1ccd8d1 100644 --- a/src/test/scala/binocular/TreasuryMovementValidatorTest.scala +++ b/src/test/scala/binocular/TreasuryMovementValidatorTest.scala @@ -454,7 +454,8 @@ class TreasuryMovementValidatorTest extends AnyFunSuite { */ private def configRefInput( withNft: Boolean = true, - bridgeStatePolicyArg: ByteString = bssPolicy + bridgeStatePolicyArg: ByteString = bssPolicy, + appended: List[Data] = Nil ): TxInInfo = TxInInfo( outRef = TxOutRef(TxId(filled(0x03, 32)), BigInt(0)), resolved = TxOut( @@ -463,7 +464,12 @@ class TreasuryMovementValidatorTest extends AnyFunSuite { if withNft then Value.unsafeFromList(PList((configNftPolicy, PList((configNftName, BigInt(1)))))) else Value.lovelace(2_000_000), - datum = OutputDatum.OutputDatum(configDatum(bridgeStatePolicyArg)), + datum = OutputDatum.OutputDatum(configDatum(bridgeStatePolicyArg) match { + // Fields a later revision APPENDED ([CFG-5]) — rev 5.6's #13 is the first. + case Data.Constr(tag, fields) if appended.nonEmpty => + Data.Constr(tag, PList.from(fields.asScala.toList ++ appended)) + case d => d + }), referenceScript = Option.None ) ) @@ -851,6 +857,47 @@ class TreasuryMovementValidatorTest extends AnyFunSuite { // (address, NFT policy, spend all use it). } + // spec [CFG-10], [CFG-5]: the registry migration APPENDS Config #13, and this validator is + // already deployed — its pin cannot move to accommodate it. So the question is not whether the + // source compiles against a longer datum but whether the UPLC on chain decodes one. It reads + // `bridge_state_policy` through the derived `ConfigDatum` decoder; if that decoder insisted on + // exactly thirteen fields, the governance Update that begins a migration would stop every + // treasury movement on the bridge. Evaluated on the DEPLOYED blueprint form, both reads. + private def deployedTmProgram = + binocular.blueprint.BinocularBlueprint + .program("TreasuryMovementContract") + .$(binocular.blueprint.BinocularBlueprint.bytesParam(oracleHash)) + .$(binocular.blueprint.BinocularBlueprint.bytesParam(configNftPolicy)) + .$(binocular.blueprint.BinocularBlueprint.bytesParam(configNftName)) + .deBruijnedProgram + + private val field13Values: List[(String, Data)] = List( + "a migration in progress (#13 = the previous registry)" -> Data.B(filled(0xb2, 28)), + "a migration ended (#13 empty)" -> Data.B(ByteString.empty) + ) + + for (what, field13) <- field13Values do { + test(s"deployed TM confirm accepts a Config with #13 appended: $what") { + val sc = scriptContext( + confirmRdmr(), + cfgRefs = List(configRefInput(appended = List(field13))) + ) + val result = deployedTmProgram.applyArg(sc.toData).evaluateDebug + assert(result.isSuccess, s"expected success, got: $result") + } + + test(s"deployed TM mint accepts a Config with #13 appended: $what") { + val sc = mintContext( + BigInt(1), + postRdmr, + PList.from(List(configRefInput(appended = List(field13)), bssRefInput())), + PList.from(List(mintedTmOutput())) + ) + val result = deployedTmProgram.applyArg(sc.toData).evaluateDebug + assert(result.isSuccess, s"expected success, got: $result") + } + } + test("block header not in oracle's confirmed-blocks root fails") { // Same merkle-root (bytes 36..68 = txid), but a different nonce → a different block hash // that the oracle's MPF does not contain. Isolates the MPF membership check. diff --git a/src/test/scala/binocular/cli/UpdateConfigCommandTest.scala b/src/test/scala/binocular/cli/UpdateConfigCommandTest.scala index 2aadb96..1e73a9d 100644 --- a/src/test/scala/binocular/cli/UpdateConfigCommandTest.scala +++ b/src/test/scala/binocular/cli/UpdateConfigCommandTest.scala @@ -2,7 +2,8 @@ package binocular.cli import binocular.cli.commands.UpdateConfigCommand import binocular.cli.commands.UpdateConfigCommand.ParamEdits -import binocular.watchtower.{AuthorizationMethod, ConfigDatum, ConfigParams, ScheduleParams} +import binocular.cli.commands.UpdateConfigCommand.RegistryEdit +import binocular.watchtower.{AuthorizationMethod, ConfigDatum, ConfigParams, DeployedConfig, ScheduleParams} import org.scalatest.funsuite.AnyFunSuite import scalus.cardano.onchain.plutus.prelude.{List as PList, Option as SOption} @@ -135,24 +136,105 @@ class UpdateConfigCommandTest extends AnyFunSuite { } test("decodeDeployed round-trips the rev-5.5 datum") { - assert(UpdateConfigCommand.decodeDeployed(config.toData) == Right(config)) + val d = UpdateConfigCommand.decodeDeployed(config.toData) + assert(d == Right(DeployedConfig(config, Nil))) + assert(d.toOption.get.toData == config.toData) } - // Appending is the legal datum evolution (config.ak's Update accepts any datum), and READERS - // ignore unknown trailing fields — but this command re-encodes the whole datum, so rewriting a - // grown datum would silently truncate it. It must be refused, not carried. - test("decodeDeployed refuses a datum that grew past the rev-5.5 layout") { - val grown = config.toData match { - case Data.Constr(0, fields) => - Data.Constr(0, PList.from(fields.asScala.toList :+ (Data.I(BigInt(99)): Data))) - case other => fail(s"config datum is not a Constr 0: $other") + /** The rev-5.5 datum with `extra` appended ([CFG-5]). */ + private def grown(extra: Data*): Data = config.toData match { + case Data.Constr(0, fields) => Data.Constr(0, PList.from(fields.asScala.toList ++ extra)) + case other => fail(s"config datum is not a Constr 0: $other") + } + + // This was a refusal: the command re-encoded the typed record, so a grown datum would have + // lost its appended fields. It now carries them — which is what lets it write rev 5.6's #13 and + // keep updating every other field once #13 exists. + test("an update of a grown datum carries the appended fields through verbatim") { + val datum = grown(Data.B(ByteString.fromHex("b2" * 28)), Data.I(BigInt(99))) + val deployed = UpdateConfigCommand.decodeDeployed(datum).toOption.get + assert(deployed.config == config) + val edited = deployed.copy(config = + UpdateConfigCommand.rewrite( + deployed.config, + None, + None, + None, + None, + ParamEdits(schedule = Map("tm_batch_interval" -> BigInt(600))) + ) + ) + val out = edited.toData match { + case Data.Constr(0, fs) => fs.asScala.toList + case other => fail(s"not a Constr 0: $other") } - val out = UpdateConfigCommand.decodeDeployed(grown) - assert(out.isLeft) - // Names both counts: the arity FOUND on chain and the one this build knows, so the - // operator can tell "binocular is behind the bridge" from "this is the wrong bridge". - assert(out.swap.toOption.get.contains("14 fields")) - assert(out.swap.toOption.get.contains(s"${UpdateConfigCommand.ConfigFieldCount}-field")) + assert(out.size == 15) + assert(out(13) == Data.B(ByteString.fromHex("b2" * 28))) + assert(out(14) == Data.I(BigInt(99))) + } + + private val newRegistry = ByteString.fromHex("c7" * 28) + + // spec [CFG-10]: the migration's governance Update. Field 9 moves and field 13 records what it + // held, in one edit — on a datum written before #13 existed, which is every deployed bridge. + test("--migrate-registry-to moves field 9 and appends the old registry as field 13") { + val deployed = UpdateConfigCommand.decodeDeployed(config.toData).toOption.get + val out = UpdateConfigCommand + .applyRegistryEdit(deployed, RegistryEdit.MigrateTo(newRegistry), banPolicyMoved = true) + .toOption + .get + assert(out.config.sposRegistryPolicyId == newRegistry) + assert(out.previousSposRegistryPolicyId == Some(config.sposRegistryPolicyId)) + val d = UpdateConfigCommand.diff(config.toData, out.toData).map(x => (x._1, x._2)).toSet + assert(d == Set((9, "spos_registry_policy_id"), (13, "previous_spos_registry_policy_id"))) + } + + // Field 13 must be what field 9 held, so the edit takes it from the datum rather than from the + // operator; and a second migration cannot begin while the first is still recorded. + test("a migration cannot begin while one is in progress, and ending one empties field 13") { + val inProgress = + UpdateConfigCommand.decodeDeployed(grown(Data.B(config.sposRegistryPolicyId))).toOption.get + val again = UpdateConfigCommand.applyRegistryEdit( + inProgress, + RegistryEdit.MigrateTo(newRegistry), + banPolicyMoved = true + ) + assert(again.isLeft && again.swap.toOption.get.contains("already in progress")) + + val ended = UpdateConfigCommand + .applyRegistryEdit(inProgress, RegistryEdit.EndMigration, banPolicyMoved = false) + .toOption + .get + assert(ended.previousSposRegistryPolicyId.isEmpty) + assert(ended.appended == List(Data.B(ByteString.empty)), "emptied, never removed ([CFG-5])") + + // Once ended, the next migration may begin. + assert( + UpdateConfigCommand + .applyRegistryEdit(ended, RegistryEdit.MigrateTo(newRegistry), banPolicyMoved = true) + .isRight + ) + } + + test("a registry migration is refused without the ban policy, and when there is none to end") { + val deployed = UpdateConfigCommand.decodeDeployed(config.toData).toOption.get + val noBans = UpdateConfigCommand.applyRegistryEdit( + deployed, + RegistryEdit.MigrateTo(newRegistry), + banPolicyMoved = false + ) + assert(noBans.isLeft && noBans.swap.toOption.get.contains("--spo-bans-policy")) + val same = UpdateConfigCommand.applyRegistryEdit( + deployed, + RegistryEdit.MigrateTo(config.sposRegistryPolicyId), + banPolicyMoved = true + ) + assert(same.isLeft) + assert( + UpdateConfigCommand + .applyRegistryEdit(deployed, RegistryEdit.EndMigration, banPolicyMoved = false) + .isLeft + ) } test("decodeDeployed refuses short and non-record datums") { From 9c824f6be042c8c4d01adc872b904a0fffa56cee Mon Sep 17 00:00:00 2001 From: Ruslan Shevchenko Date: Wed, 23 Sep 2026 12:45:59 +0300 Subject: [PATCH 2/3] feat(bridge): name the contracts release a bridge runs, and write the operator guide A bridge's contracts release is fixed at its genesis, and binocular now carries two: rev 5.5 (ft main, the preprod bridge) and rev 5.6 (ft 096f76c, the release heimdall embeds). `bridge.contracts` says which one a bridge was deployed with, and it defaults to rev5.5. The vendored blueprint for that release travels with its bytes, and it decides the two version-dependent parameterizations: the registry's added Config policy, and the ban list's Config policy in place of the registry hash. It also decides the Config arity genesis writes (13, or 14 with #13 empty). The rev 5.6 policy ids are pinned against heimdall's independent Rust derivation. A registry revision does not change the release. deploy-script-refs and register-bridge-creds now recognise a Config whose treasury still matches but whose registry has moved, and leave that half to heimdall instead of refusing. `bridge.plutus-json` defaults to empty and is refused when it cannot be read. It used to default to a sibling ft checkout and fall back silently, which made the contracts a command built with depend on that checkout's branch. docs/operator-guide.md is binocular's first guide for the people who run a bridge. It covers what binocular does for one, the `bridge` section, genesis in order across heimdall and binocular, the watchtower, and changing the Config (including the registry migration). It ends with what the common refusals mean. The README's command table, which listed commands that no longer exist, now points to it. --- Readme.md | 30 +- application-preprod-v2.conf | 10 +- docs/operator-guide.md | 259 ++++++++++++++++++ .../resources/bifrost-plutus-min-rev5.6.json | 56 ++++ src/main/resources/reference.conf | 9 +- .../BootstrapBridgeStateCommand.scala | 2 +- .../cli/commands/ConfirmTmtxCommand.scala | 7 +- .../cli/commands/DeployBridgeCommand.scala | 22 +- .../commands/DeployScriptRefsCommand.scala | 61 +++-- .../cli/commands/PegInCompleteCommand.scala | 2 +- .../cli/commands/PegInRequestCommand.scala | 2 +- .../cli/commands/PegOutCompleteCommand.scala | 2 +- .../cli/commands/PegOutRequestCommand.scala | 2 +- .../commands/RegisterBridgeCredsCommand.scala | 20 +- .../cli/commands/UpdateConfigCommand.scala | 4 +- .../scala/binocular/traffic/LiveTraffic.scala | 2 +- .../watchtower/BifrostContracts.scala | 168 ++++++++++-- .../binocular/watchtower/BridgeConfig.scala | 10 +- .../binocular/BifrostContractsTest.scala | 108 +++++++- .../binocular/FederationContractsTest.scala | 98 ++++++- 20 files changed, 784 insertions(+), 90 deletions(-) create mode 100644 docs/operator-guide.md create mode 100644 src/main/resources/bifrost-plutus-min-rev5.6.json diff --git a/Readme.md b/Readme.md index 57708bd..6c3b1d8 100644 --- a/Readme.md +++ b/Readme.md @@ -71,6 +71,10 @@ Pass a config file with `--config`: | `wallet` | Wallet mnemonic for signing | `WALLET_MNEMONIC` | | `oracle` | Oracle parameters (UTxO ref, owner) | `ORACLE_TX_OUT_REF`, `ORACLE_OWNER_PKH`, `ORACLE_START_HEIGHT` | | `relay` | TMTx relay settings | `RELAY_TMTX_POLICY_ID`, `RELAY_TMTX_ASSET_NAME` | +| `bridge` | The Bifrost bridge this binocular serves: its contracts release and identity | `BIFROST_CONTRACTS`, `CONFIG_NFT_POLICY_ID` | + +Running a Bifrost bridge — genesis, the watchtower, and changing the Config — is covered in +[docs/operator-guide.md](docs/operator-guide.md). ### Bitcoin networks @@ -101,16 +105,22 @@ All commands accept `--config ` to specify a configuration file. | `blueprint` | Print the CIP-57 Blueprint JSON | | `prove-transaction` | Prove a Bitcoin transaction's inclusion in a confirmed block | -### Bifrost relay commands - -These commands support the [Bifrost](https://github.com/nicofunke/ft-bifrost-bridge) bridge -protocol by relaying signed Treasury Movement transactions from Cardano to Bitcoin. - -| Command | Description | -|----------------|------------------------------------------------------------------| -| `relay` | Poll Cardano for TMTx UTxOs and broadcast signed Bitcoin transactions. Option: `--dry-run` | -| `create-tmtx` | Create a test TMTx UTxO on Cardano. Argument: `BTC_TX_HEX` | -| `spend-tmtx` | Spend (destroy) all TMTx UTxOs at the script address | +### Bifrost bridge commands + +These serve a [Bifrost](https://github.com/FluidTokens/ft-bifrost-bridge) bridge. What each is for, +and in what order, is in [docs/operator-guide.md](docs/operator-guide.md). + +| Command | Description | +|---------|-------------| +| `watchtower` | Oracle sync, TM relay, TM confirm, peg-out completion and the proof API, in one process | +| `relay` / `confirm-tmtx` / `serve-proofs` | The same workers, one at a time | +| `deploy-bridge` | Genesis: the Config, the completion contracts, the treasury and the SPO registry and ban list | +| `deploy-script-refs` | Publish the bridge's heavy scripts as reference scripts | +| `register-bridge-creds` | Register the withdraw reward accounts, if genesis stopped partway | +| `update-config` | Change the Config in place (governance), including a registry migration | +| `tm-script` | Print the TM validator's policy id, address and CBOR | +| `pegin-request`, `pegin-complete`, `peg-out-request`, `peg-out-complete` | Peg-in and peg-out, for testing and demos | +| `deposit-proof`, `spi-proof` | One proof, for one deposit outpoint | ### Other diff --git a/application-preprod-v2.conf b/application-preprod-v2.conf index 4039cad..8de9e3a 100644 --- a/application-preprod-v2.conf +++ b/application-preprod-v2.conf @@ -117,10 +117,12 @@ binocular { } bridge { - # Empty on purpose: BifrostBlueprint.resolve falls back to the blueprint vendored in the jar - # (/bifrost-plutus-min.json), verified identical to ft-bifrost-bridge/onchain/plutus.json for - # all 13 validators. dev.lantr.io has no ft checkout, so a path here would silently resolve to - # the packaged copy anyway; saying so is clearer than a path that does not exist. + # The contracts release this bridge was deployed with. It stays rev5.5 after the registry + # revision: that replaces the registry and ban list (heimdall's), not config.ak or the peg/TM + # scripts binocular spends. + contracts = "rev5.5" + # Empty: the blueprint packaged for `contracts` (/bifrost-plutus-min.json for rev5.5), which + # is byte-identical to ft-bifrost-bridge main for all 13 validators. plutus-json = "" # --- genesis inputs, fixed before deploy-bridge --- diff --git a/docs/operator-guide.md b/docs/operator-guide.md new file mode 100644 index 0000000..110b19d --- /dev/null +++ b/docs/operator-guide.md @@ -0,0 +1,259 @@ +# Operating binocular for a Bifrost bridge + +This guide is for the people who **run a bridge**: whoever deploys it, holds its Config's update +key, and runs its watchtower. It covers standing a bridge up, running binocular beside it, and +changing its Config afterwards. + +It is not for stake pool operators. An SPO runs heimdall, and its guide is +[heimdall's operator guide](https://github.com/lantr-io/heimdall/blob/main/docs/operator-guide.md). +It is not for depositors either. The peg-in and peg-out commands binocular ships are there for +testing and demos. They are listed at the end. + +--- + +## What binocular does for a bridge + +| Role | Commands | Runs | +|---|---|---| +| **Oracle**: Bitcoin block headers on Cardano, which every peg-in proof and TM confirm reads | `init`, `run`, `update-oracle`, `verify-oracle` | continuously | +| **Watchtower**: relays signed treasury movements to Bitcoin, confirms them on Cardano, completes paid peg-outs, serves proofs | `watchtower` (or `relay`, `confirm-tmtx`, `serve-proofs` separately) | continuously | +| **Genesis**: mints the bridge's Config, the completion contracts, the treasury and the SPO registry and ban list | `deploy-bridge`, `deploy-script-refs`, `register-bridge-creds` | once | +| **Governance**: changes the Config in place | `update-config` | when you decide to | + +heimdall covers the SPO side: the roster, distributed key generation, signing, and a registry +revision's registry and ban list. The two meet in the Config. binocular writes it at genesis and +updates it, and every heimdall reads it. + +--- + +## Install and run + +Build the jar and run it as described in the [README](../Readme.md#running-as-a-standalone-jar). The +NixOS service used for the preprod bridge, and how a new jar is deployed to it, are in +[deploy/README.md](../deploy/README.md). + +Every command takes `--config `. Settings are read in this order, highest first: +environment variables, the `--config` file, `application.conf`, `reference.conf`. The shipped +`reference.conf` documents every key and its environment variable. + +Keep **one config file per bridge**. Everything in its `bridge` section describes one deployment, +and most of it is copied from what `deploy-bridge` printed for that deployment. + +--- + +## The `bridge` section + +The settings that identify the bridge: + +| Key | What it is | Set from | +|---|---|---| +| `contracts` | the ft-bifrost-bridge contracts release the bridge was **deployed with**: `rev5.5` or `rev5.6` | your choice at genesis, then never changed | +| `config-nft-policy-id` | the Config NFT policy, which is the bridge's identity | `deploy-bridge` output | +| `completed-peg-ins-one-shot-ref`, `bridge-state-one-shot-ref` | the one-shot outpoint genesis spent (the same value under both keys) | `deploy-bridge` output | +| `bridged-token-policy-id` | the fBTC policy | `deploy-bridge` output | +| `plutus-json` | a blueprint file replacing the packaged one, for developing the validators | empty | + +The genesis inputs (`y-federation-hex`, `federation-csv-blocks`, `pegin-refund-timeout-blocks`, +`ban-schedule`, `initial-btc-treasury-utxo`, `initial-btc-treasury-amount-sat`) are read by +`deploy-bridge` only. After genesis every node reads their published values from the Config, so +editing them in a file changes nothing. + +### `contracts` + +binocular carries two releases of the ft-bifrost-bridge contracts, and `contracts` says which one +**this bridge** was deployed with. It is a property of the bridge, not of the binocular version. + +- **`rev5.5`** is what ft-bifrost-bridge `main` builds, and what the preprod bridge runs. It is + the default, so a config file written before this key existed keeps working. +- **`rev5.6`** adds the single-use registration signatures and the `Migrate` branch that lets a + running bridge revise its registry. Choose it for a new bridge that should run those contracts. + +Of the scripts binocular derives, three differ between the releases: + +- `config.ak`: same parameters, different code, so a different Config policy id. +- `spos_registry`: rev 5.6 adds the Config NFT policy as a parameter. +- `spo_bans`: its first parameter is the registry policy in rev 5.5 and the Config NFT policy in + rev 5.6. + +A rev 5.6 genesis also writes a Config with 14 fields rather than 13. Field #13 starts empty. + +**It never changes on a running bridge, and a registry revision does not change it either.** A +revision replaces the registry and the ban list, which heimdall deploys. The Config, the treasury, +the peg scripts and the TM validator, the ones binocular spends, stay those of the release the +bridge was deployed with. A bridge deployed on `rev5.5` and revised afterwards keeps +`contracts = "rev5.5"`. + +A wrong value does not go unnoticed. `update-config` derives the Config policy from the declared +release and refuses when it does not match `config-nft-policy-id`. + +### `plutus-json` + +Empty by default: binocular uses the blueprint packaged for `contracts`. Set it to a `plutus.json` +path only while developing the Aiken validators. A path that cannot be read is refused rather than +replaced by the packaged blueprint. Earlier versions defaulted to a sibling ft-bifrost-bridge +checkout and fell back silently, so the contracts a command used depended on which branch that +checkout was on. + +--- + +## Standing a bridge up + +Genesis is one binocular command, but it needs inputs from heimdall first, and heimdall's SPOs +need its outputs afterwards. + +1. **Form the federation key.** The federation runs heimdall's ceremony, in the appendix + "forming the initial federation" of heimdall's guide, or uses a single seed on a test bridge. + `heimdall bootstrap-treasury` then prints the key and the genesis treasury address. Put the key + in `bridge.y-federation-hex`. +2. **Fund the genesis treasury** on Bitcoin at that address, and put the outpoint and amount in + `bridge.initial-btc-treasury-utxo` and `bridge.initial-btc-treasury-amount-sat`. +3. **Have a live oracle.** The TM validator and the peg-in validator are parameterized by the + oracle's policy. For a new one, use `init`, then keep `run` (or `watchtower`) going. +4. **Choose `contracts`** and the genesis inputs: `federation-csv-blocks`, + `pegin-refund-timeout-blocks` (it must exceed the CSV) and `ban-schedule`. These are published + at genesis and cannot be changed later. The CSV and refund timeout are hashed into the Bitcoin + addresses, and the ban schedule into the ban policy. +5. **Fund the sponsor wallet** with at least two clean, ADA-only UTxOs of 5 ADA or more. Genesis + spends two one-shots in two transactions, because the registry, the ban list and the Config + together exceed Cardano's 16 kB transaction limit. +6. **Deploy:** + + ```bash + binocular --config bridge.conf deploy-bridge --dry-run + binocular --config bridge.conf deploy-bridge + ``` + + The first transaction bootstraps the federation: the treasury state, the registry root and the + ban root. The second mints the Config, the completed-peg-ins trie and the bridge-state + singleton, and registers the peg-in and peg-out reward accounts. The command prints every value + to copy into this config file, plus the Config NFT policy heimdall's SPOs configure. +7. **Publish the reference scripts:** + + ```bash + binocular --config bridge.conf deploy-script-refs + ``` + + This publishes the heavy scripts once for everyone, so the completion transactions and the SPOs' + registration transactions stay under the size limit. It skips whatever is already published. + Run `register-bridge-creds` only if `deploy-bridge`'s second transaction stopped partway. +8. **Tell the SPOs the Config NFT policy.** From there they follow heimdall's guide. + +--- + +## Running the watchtower + +```bash +binocular --config bridge.conf watchtower +``` + +`watchtower` runs the oracle sync, the TM relay and the TM confirm in one process. It also serves +the proof API and, after each confirm, completes the peg-outs it paid. `bridge.por-sweeper` and +`bridge.proof-server` (port `proof-server-port`) turn those two off, and the `notifications` +section sends its events to a chat. Confirming needs `bridge-state-one-shot-ref`, and the watchtower refuses to start +without it. + +Everything the watchtower does is permissionless. It needs a funded wallet for fees, not a key the +bridge trusts. Anyone may run one, and more than one is fine. + +--- + +## Changing the Config + +The Config is updated in place by `update-config`. The transaction must be signed by the Config's +`update_auth` key, which `deploy-bridge` set to `oracle.owner-pkh`, so run it with that wallet. + +**Always dry-run first.** A dry run computes the new datum and prints every field that changes, +old and new, without submitting: + +```bash +binocular --config bridge.conf update-config --dry-run +``` + +Everything you name goes into **one** transaction. That matters when you swap a validator whose +dependents must flip at the same moment. + +| Options | Fields | Notes | +|---|---|---| +| `--bridge-state-policy`, `--tm-script-hash`, `--peg-in-withdraw-hash`, `--peg-out-withdraw-hash` | the script hashes | a validator redeploy; swap its dependents in the same call | +| `--fee-rate`, `--per-pegout-fee`, `--min-peg-out` | operational parameters | every SPO's TM builder reads them from the next batch | +| `--schedule NAME=VALUE` (repeatable) | the epoch and TM schedule | checked against the spec's constraints; see below | +| `--spo-bans-policy` | #8, the ban list | moves when the registry does | +| `--migrate-registry-to`, `--end-registry-migration` | #9 and #13 | a registry revision; see below | + +A schedule edit prints the batch grid before and after, and refuses a schedule that breaks a spec +constraint. Nothing on chain would refuse it, and the failure is silent: a bridge that idles for +days looks like one whose SPOs are down. `--allow-unsafe-schedule` publishes it anyway, for a test +bridge. + +The ban schedule is not listed because it is not a setting you can move by itself. It is an input +to the ban policy id, so changing it means deploying a new ban list. + +### A registry revision + +A contracts release can replace the SPO registry, and with it the ban list. heimdall carries every +registration across with no cold key. Operators install the new heimdall, and the federation runs +one command for the stragglers. binocular's part is the single governance Update in the middle, +and ending the window afterwards: + +```bash +binocular --config bridge.conf update-config \ + --migrate-registry-to --spo-bans-policy --dry-run +# … every pool crosses … +binocular --config bridge.conf update-config --end-registry-migration --dry-run +``` + +`--migrate-registry-to` moves #9 and writes the registry #9 held into #13. #13 is taken from the +datum, not typed, so it cannot name the wrong list. The option requires `--spo-bans-policy` in the +same Update, and refuses while another migration is still recorded. `--end-registry-migration` +empties #13 and never removes the field. + +The full runbook covers deploying the new registry and ban list, carrying the pools across, bans, +and checks. It is heimdall's appendix "carrying a bridge across a registry revision", because +heimdall does everything except the Update. + +What changes for binocular: nothing in its config file. `contracts` stays. `deploy-script-refs` +and `register-bridge-creds` notice that the Config names a revised registry and skip the SPO half +with a message saying so, because heimdall publishes those reference scripts and registers that +credential. binocular reads a 14-field Config and writes it back intact. + +--- + +## Upgrading binocular + +For the NixOS service, `deploy/deploy.sh user@host --v2` builds, copies and restarts +([deploy/README.md](../deploy/README.md#routine-deploys-new-jar-only)). `--no-restart` stages the +jar first. + +A binocular upgrade never changes `contracts`. A binocular that knows a newer contracts release +still runs a bridge deployed on an older one. + +--- + +## When something is wrong + +| You see | What it means | +|---|---| +| `Derived config policy … does not match bridge.config-nft-policy-id` | `contracts` is not the release the bridge was deployed with, or the one-shot ref is wrong. | +| `bridge.plutus-json = '…' is not readable` | The override points nowhere. Empty it to use the packaged blueprint. | +| `bridge.contracts = '…' is not a contracts release this binocular knows` | A typo, or a release newer than this binocular. | +| `federation half skipped — the Config names a revised registry …` from `deploy-script-refs` | Expected after a registry revision: heimdall publishes those scripts. | +| `derived treasury_info policy … does not match the Config's` | The one-shot this command derived from is not the bridge's, or `contracts` is wrong. | +| `a registry migration is already in progress` from `update-config` | End the current one with `--end-registry-migration` first. | +| `--migrate-registry-to needs --spo-bans-policy in the same Update` | The ban list moves with the registry. Pass both. | + +--- + +## Testing and demo commands + +These exist for testing a bridge end to end and for demos. None of them is needed to run one. + +| Command | Does | +|---|---| +| `pegin-request`, `pegin-complete`, `sign-pegin-msg` | a peg-in, from the depositor's side | +| `peg-out-request`, `peg-out-complete` | a peg-out, and completing paid ones | +| `deposit-proof`, `spi-proof`, `serve-proofs` | the proofs a frontend fetches, one-off or as a server | +| `traffic-address` | the demo Bitcoin funding address | +| `tm-script` | the TM validator's policy id, address and CBOR | +| `bootstrap-bridge-state` | mints a replacement bridge-state singleton (recovery) | +| `migrate-script-refs` | moves reference scripts to the native holding address | +| `set-state`, `attack` | oracle recovery and adversarial testing | diff --git a/src/main/resources/bifrost-plutus-min-rev5.6.json b/src/main/resources/bifrost-plutus-min-rev5.6.json new file mode 100644 index 0000000..463cb28 --- /dev/null +++ b/src/main/resources/bifrost-plutus-min-rev5.6.json @@ -0,0 +1,56 @@ +{ + "validators": [ + { + "title": "bitcoin/bridge_state.bridge_state.mint", + "compiledCode": "59034d0101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae0034888888896600330013004375401323008300900191191919800800802112cc00400600713233225980099b910070028acc004cdc78038014400600c805226600a00a60200088050dd718048009bab300a001300c0014028297adef6c609b874800a6e1d20009ba5480092222223232980098059baa00191119199119801001000912cc00400600713233225980099b910070028acc004cdc78038014400600c809a26600a00a60320088098dd718090009bad30130013015001404c66014008006290004c03c022601e00491112cc004c02001226464b300130160018992cc004c030dd69809800c56600266e3d2210342535300375c602400315980099198008009bac3017301830183014375400c44b30010018a508acc004c96600266ebcc064c058dd5180c980b1baa001300d33018375200c97ae089807cc004dd59808980b1baa001803522010342535300402514a080a0c0600062946266004004603200280990164566002601660246ea8c8cc004004dd6180b980a1baa0062259800800c530103d87a80008992cc004cdd7980c980b1baa00101c899ba548000cc0600052f5c1133003003301a0024050603000280b229462941011459011459011459011180a800c59013198059bab30143015301530153015301137540060026eb8c04cc040dd5002c56600260120091329800980a000cc050c05400664660020026eb0c054c048dd5002112cc004006297ae0899912cc004cdd7980c180a9baa3018301537546020602a6ea8008c030cc05cdd480925eb8226602e00466008008003133004004001404c602c002602e00280a122259800980c000c4c8c966002601c602a6ea80062b3001300f98009bab3011301637546022602c6ea800a02748810040251300e375a602a6466ec0dd4180b0009ba7301700137546032602c6ea8006294101445901419199119801001000912cc0040062980103d87a80008992cc004cdd7802180c000c4cdd2a400066036603200297ae0899801801980e801202e301b00140646eacc064c068c068c068c068c068c068c068c068c068c058dd500418061980b980c180a9baa0014bd70180b800c590150c040dd5002c528201c4038300e300f001300e006452689b2b200401" + }, + { + "title": "bitcoin/bridge_state.bridge_state.spend", + "compiledCode": "59034d0101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae0034888888896600330013004375401323008300900191191919800800802112cc00400600713233225980099b910070028acc004cdc78038014400600c805226600a00a60200088050dd718048009bab300a001300c0014028297adef6c609b874800a6e1d20009ba5480092222223232980098059baa00191119199119801001000912cc00400600713233225980099b910070028acc004cdc78038014400600c809a26600a00a60320088098dd718090009bad30130013015001404c66014008006290004c03c022601e00491112cc004c02001226464b300130160018992cc004c030dd69809800c56600266e3d2210342535300375c602400315980099198008009bac3017301830183014375400c44b30010018a508acc004c96600266ebcc064c058dd5180c980b1baa001300d33018375200c97ae089807cc004dd59808980b1baa001803522010342535300402514a080a0c0600062946266004004603200280990164566002601660246ea8c8cc004004dd6180b980a1baa0062259800800c530103d87a80008992cc004cdd7980c980b1baa00101c899ba548000cc0600052f5c1133003003301a0024050603000280b229462941011459011459011459011180a800c59013198059bab30143015301530153015301137540060026eb8c04cc040dd5002c56600260120091329800980a000cc050c05400664660020026eb0c054c048dd5002112cc004006297ae0899912cc004cdd7980c180a9baa3018301537546020602a6ea8008c030cc05cdd480925eb8226602e00466008008003133004004001404c602c002602e00280a122259800980c000c4c8c966002601c602a6ea80062b3001300f98009bab3011301637546022602c6ea800a02748810040251300e375a602a6466ec0dd4180b0009ba7301700137546032602c6ea8006294101445901419199119801001000912cc0040062980103d87a80008992cc004cdd7802180c000c4cdd2a400066036603200297ae0899801801980e801202e301b00140646eacc064c068c068c068c068c068c068c068c068c068c058dd500418061980b980c180a9baa0014bd70180b800c590150c040dd5002c528201c4038300e300f001300e006452689b2b200401" + }, + { + "title": "bitcoin/bridged_token.bridged_token.mint", + "compiledCode": "590294010100229800aba2aba1aba0aab9faab9eaab9dab9a9bae0024888888896600264653001300900198049805000cdc3a400130090024888966002600460126ea800e264b30013003300a375400b1323259800980880144c8c8cc88c96600266e3cdd719801800a400801113259800980b800c4c96600266e3cdd71809800a45046653415400899912cc004cdc4240006eb4c05800e2660026eacc008c058dd500699ba548008cc060cc01c015200c4bd7044cc004dd59801180b1baa00d3374a90011980c19803802a401c97ae040504603060326032603260326032603200244646600200200644b30010018a508acc004cdd7801980b980d800c528c4cc008008c07000501620328b202430160018b2028330023756602a602c602c602c602c60246ea80240222c8080c8c96600266e212000323322330020020012259800800c00e2646644b300133722910106424946434647000028acc004cdc7a44106424946434647000028800c01901744cc014014c0740110171bae3016001375a602e002603200280b8cc010dd59801980a1baa3003301437540040222900044c96600266e1d200430133754003130143754602e60286ea80062c8090c058c05cc05cc04cdd5180118099baa0018b2022330033758600260246ea8024dd6980a98091baa00c230153016001225980099b894800000626600600400316403c4464646600200200844b3001001801c4c8cc896600266e4401c00a2b30013371e00e0051001803202a899802802980d802202a375c60280026eacc054004c05c0050150a5eb7bdb180c004004889660026010003130130028cc00400e6028005337009000800a00640391640386eb4c03c004c02cdd5002c590091bae300d300a375400714a08040601200260086ea802629344d9590021" + }, + { + "title": "bitcoin/completed_peg_ins_merkle_tree.completed_peg_ins_merkle_tree_validator.mint", + "compiledCode": "5908180101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae00348888888966003300130043754013230083009300900191191919800800802112cc00400600713233225980099b910070028acc004cdc78038014400600c805226600a00a60200088050dd718048009bab300a001300c0014028297adef6c609ba54800a6e1d20029b87480012222223232980098059baa00198078044c03c009222598009803001c4c8c966002602a0031332259800980b800c4c96600260186eb4c0500062b300159800980598099baa323300100137586030602a6ea8020896600200314c103d87a80008992cc004cdd7980d180b9baa00101d899ba548000cc0640052f5c1133003003301b0024054603200280ba29462941012456600266e3d2210343504900375c602600315980099baf4c012ad87b9fd8799f58200000000000000000000000000000000000000000000000000000000000000000ffff00300f3014375400713375e602e60286ea800ccdd2a40006602c601a6602c6ea40152f5c06602c980103d87a80004bd70452820248a50404914a080922c8090c0580062c80a0c050004cc02cdd5980a180a980a980a980a98089baa0040028b202432330010013758601860226ea8010896600200314bd7044cc896600266ebcc05cc050dd5180b980a1baa002300d33016375200a97ae089980b00119802002000c4cc010010005012180a800980b000a026375c6024601e6ea80122b3001300700389919912cc004c024c044dd500244c8c8cc8966002603400713322323233225980099baf301b0013374a90021980f180a9980f1ba90024bd7025eb8233001301c00191192cc004c05800626464b300130250028024590221bae3023001301f3754007159800980b800c4c8c966002604a0050048b2044375c6046002603e6ea800e2c80e901d180e9baa00291192cc004c058006264646644b300130270038034590241bae3024001375a60480046048002603e6ea800e2b3001301700189919912cc004c098006264b3001301a30223754003132323298009bae30290019bad30290039bae3029002488966002605a00900c8b20541814800981400098119baa0018b204230250018b2046375a60460026048002603e6ea800e2b30013370e9002000c4c8c8ca60026eb8c0940066eb4c09400e6eb8c09400922259800981480240222c8130604a0026048002603e6ea800e2c80e901d203a301d37540052232330010010032233003001300200248888c966002603060406ea80162646644b30013028001899192cc004c0740062646644b3001302d001899192cc004c0880062646644b300130320018998079bac3031001225980080140422660246066004260026068004818a2c8178dd69817800981800098159baa0028acc004c08c006264653001375c606000330310019bad303000248896600260680051330113758606600444b300100280944cc050c0d40084c004c0d80090334590310c0c0004c0acdd500145902920523029375400260580031640a86eb8c0a8004c0ac004c098dd50014566002603c00313232323232323232323298009bac30330019bad30330099bae30330089bad30330079bad30330069bac30330059bac30330049bad30330039bae3033002488888888966002607a01513322598009819181d1baa00289919192cc004c10800a2660426082006264b300130360018992cc004c11000626464b300130390018992cc004c11c00626604c608c00201316411060846ea800a2b3001303a00189919194c004dd69824000cdd69824001cdd698240012444b3001304c0048074590490c120004c11c004c108dd50014590402080304037540026086003164104607e6ea800a2b300130370018acc004c0fcdd500140162c82022c81e903d181e9baa0018b207e30400013040001303b37540051640e4607802626603400844b300100289980e002912cc00400a26603c01a44b300100280fc4cc084c1080084c004c10c00904044cc07cc1000084c004c10400903e44cc074c0f80084c004c0fc00903c45903a0c0cc004c0c8004c0c4004c0c0004c0bc004c0b8004c0b4004c0b0004c0ac004c098dd5001459024204830243754002604e0031640946eb4c094004c098004c084dd5002c5901f0acc005660026030603e6ea8c024c080dd50024528c528203c899198008009bab30243025302530253025302530253021375402844b30010018a508acc004c966002603660446ea8006266e3cdd7181318119baa0010098a5040846042604a00314a313300200230260014080811a294101e22c80d0dd719800992cc004cdc4240006466446600400400244b3001001801c4c8cc896600266e45220106424946434647000028acc004cdc7a44106424946434647000028800c01901f44cc014014c09401101f1bae301e001375a603e002604200280f8cc058dd59802980e1baa3005301c37540040322900044c96600266e1d2004301b37540031301c3754603e60386ea80062c80d0c058c06cdd51802180d9baa0018b2032330013758600660346ea8034dd6980e980d1baa00c48030ca60026002003375a600860366ea80366eacc078c07cc07cc07cc07cc07cc07cc07cc07cc07cc06cdd50072444b300133712900000144cc00c00400a2c80e0444b3001301400189810001466002007302100299b80480040050032036225980099b89480000062660060040031640646004004444b300130100018980e001466002007301d00299b8048004005003202e2301a301b0018b202e375a602e0026eb4c05c008c05c004c048dd500245901018098009809980a00098079baa0048a5040348068601c601e002601c00c8a4d13656400801" + }, + { + "title": "bitcoin/config.config.mint", + "compiledCode": "590b590101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae0039bad00248888888896600330013005375401523009300a300a0019b87480026e952000918049805180518051805000c88c8c8cc004004010896600200300389919912cc004cdc8803801456600266e3c01c00a2003006402d1330050053011004402c6eb8c028004dd598058009806800a01614bd6f7b6304dc3a4009370e90034dc3a400523009300a0019b87480066e952002488888888888a6002602a019301400c9112cc004c0340062602e00519800801cc06000a66e012001001400c809244646600200200644b30010018a6103d87a80008992cc004c0100062601c6603000297ae0899801801980d00120283018001405922329800800ccc02800c00a9000200222259800801440062653001004980d801cc8cdc01bad3018002003375c602c0028020c064009017488c966002601a00313259800980c800c4c8c96600260200031323259800980e801401e2c80d0dd7180d800980b9baa0028acc004c02800626464b3001301d002803c5901a1bae301b001301737540051598009806000c4c8c966002603a0050078b2034375c6036002602e6ea800a2b3001300b001899192cc004c07400a00f1640686eb8c06c004c05cdd5001456600266e1d20080018991919912cc004c07c00e0131640706eb8c070004dd7180e001180e000980b9baa0028b202a405480a9015202a30153754002603000316405860286ea800e2b300130070018acc004c050dd5001c00a2c80aa2c809101218091baa00291119199119801001000912cc00400600713233225980099b910070028acc004cdc78038014400600c80c226600a00a603c00880c0dd7180b8009bad3018001301a00140606601600800629000244444453001301b007980d980e003cc014016446600c004466ebcc078c06cdd5000801244446644b30013017002899192cc004cdc424000003159800980c980f9baa330053758604660406ea8038c060cc088dd480e998111ba801c4bd7044c8c966002602e60426ea8006264b3001301c302237540031323232323232323232323232323298009bae3034001981a006cdd7181a0064dd7181a005cdd7181a0054dd7181a004cdd7181a0044dd7181a003cdd7181a0034dd7181a002cdd7181a0024dd7181a001cc0d0009222222222222259800982100744cc0a0c10406c566002606e607a6ea803226464646464646464653001375a6094003375a6094011375a609400f375a609400d375a609400b375a6094009375a6094007375a6094004911111112cc004c14c026264b30013049304f375400313232323232323232323298009bad305d0019bad305d00a9bad305d0099bad305d0089bad305d0079bad305d0069bad305d0059bad305d0049bad305d0039bad305d002488888888896600260d0017159800982e98319baa0278991919912cc004c1b000e2b30013375e60d660d06ea8c1acc1a0dd5024182c198351ba904a4bd70456600260b6093159800982dcc004dd5982f98341baa0568255221064249464346470041451305b98009bab305a3068375409104aa450642494643464700414514a083322941066452820cc8b20d2375a60d20026eb8c1a4008c1a4004c190dd5013c590624590650c174004c170004c16c004c168004c164004c160004c15c004c158004c154004c140dd5000c5904e1829008c590500c128004c124004c120004c11c004c118004c114004c110004c10c004c0f8dd500645903c45903f0c0d0004c0cc004c0c8004c0c4004c0c0004c0bc004c0b8004c0b4004c0b0004c0ac004c0a8004c0a4004c0a0004c08cdd5000c59021181298111baa0018b2040301b30213754002660066eb0c068c080dd5007240011640791598009808800c4c04660026eacc05cc080dd5007400a9110642494643464700402514a080f101e198051bab3016301f375401a0026eb8c084c078dd5002c56600260220051323322332259800980e000c56600260466ea802e005164091159800980b000c56600260466ea802e0051640911640848108566002603460406ea800626464b3001301c302237540031332259800980f18121baa001899192cc004c068c098dd5000c4c9660026042604e6ea8042264b3001302d0018992cc004c07cc0a4dd5181218151baa0018acc00401e2b30013375e605a60546ea8004c0b4c0a8dd5180e18151baa0058acc004c8cdd79ba630013756603a60566ea8008dd318009bab301d302b3754603a60566ea80188c8cc004004008896600200314bd6f7b63044ca60026eb8c0b40066eacc0b800660640049112cc004cdc8a45000038acc004cdc7a441000038800c401502f44cc0cccdd81ba9003374c0046600c00c0028178606000281722b3001301d98009bab301c302a3754003003a4410642494643464700404d1301d330153756603860546ea800400e2941028452820508a5040a114a081422c8140c0b00062c8150c8cc004004dd6181198149baa0172259800800c52f5c1133225980099baf302f302c3754605e60586ea8008c070cc0b8dd4802a5eb8226605c0046600800800313300400400140a8605a002605c002815a2b30010058acc004c064cc04cdd5980f98141baa0160018acc004c06660026eacc07cc0a0dd500b4006911064249464346470040451301998009bab301f3028375402d375c6601600e900a52210642465254525900404514a0813229410264528204c40986eb8c0a8c09cdd5000c59025181498131baa3029302637546030604c6ea8004c0a0c094dd5000c59023194c0040064440039800981398121baa0029bac3027302437540253758602c60486ea804a6eacc09cc0a0c0a0c0a0c0a0c0a0c0a0c090dd50092444464b300130220018981099815981618149baa0053302b302c302d302d302d302d302d302d302d302d3029375402e97ae08acc004c0700062603266056605860526ea8014cc0acdd380225eb822b3001301e001899ba548010cc0acc0b0c0a4dd5002998159ba60024bd704566002603a00313374a900319815981618149baa0053302b30203029375402e97ae089919ba548020cc0b0c0b4004cc0b0c0b4c0b8004cc0b0dd3802998161ba70043302c374c00697ae03029375400a8139027204e409c604e6ea801080088a6002444b3001301b3027375400713259800cc00401a4440033374a9002198159ba90013302b374c00697ae0401914a31980080348880066032660566ea4004cc0acdd380125eb81006204e375c605660506ea800e2c81324444464b30013024302a375400319800804488800e605c60566ea8c0b8c0acdd51817181798159baa302e302b3754003002801a0108a5040a46602c006466e25200298009bab301d302b3754603a60566ea800600d0054051232598009810000c4c8c8c8cc004004dd618169817001912cc00400629422b30013371e6eb8c0b800400e2946266004004605e002814902c1bae302b00130273754005159800980d000c4c8c8c8cc004004dd618169817001912cc00400629422b30013375e605c60566ea8c0b8c0acdd51817181798159baa302e0010038a518998010011817800a05240b0603066054605600297ae030273754005159800980e000c4c8c8c8cc004004dd598169817001912cc00400629422b30013375e0066054605c00314a3133002002302f00140a48160c060cc0a8c0ac0052f5c0604e6ea800a2b3001301b0018994c004c084dd6981418159980f1bab302b302c001375c60560034a14a28130c09cdd500144c8c8c8ca60020112220029bae302e0049bae302e0039bac302e0019bac302e0029bab302e302f0014020605c002605a0026058002604e6ea8009025204a40948128c094dd5000a002330083758604c60466ea80440122c8108c8cc0340044004cc014005200030213754604860426ea80062c80f8c080dd5004981100098111811800980f1baa0058b2038407060366ea800c896600266e252000001899802001000c5901c08a4d13656400c1" + }, + { + "title": "bitcoin/fault_verifier_equivocation.fault_verifier_equivocation.mint", + "compiledCode": "59073c010100229800aba2aba1aab9faab9eaab9dab9a9bae002488888896600264653001300800198041804800cdc3a400130080024888966002600460126ea800e266446644b300130060018992cc004c048006264b30013008300f375400313232323232323298009bae30190019bad30190079bae30190069bae30190059bae30190049bae30190039bae3019002488888896600260420110128b203e180c800980c000980b800980b000980a800980a00098081baa0018b201c30110018b2020300e37540111598009801800c566002601c6ea802200516403d16403080604ca60024465300100199802001801520004004444b30010028800c4ca600200930160039919b80375a60280040066eb8c048005004180a00120269b87481024602060226022602260220029112cc004c020c03cdd5005466002602460206ea802a46026602800323013301430140019112cc004c014dc6801c56600266e1d208001371a00319800801cdc9001400576a8a50404514a0808922223259800cc0040066eb8c00cc054dd5002cdd7180b980c180c180c180a9baa0054009159800cc0040066eb8c018c054dd5002cdd7180b980c180c180c180c180c180a9baa0054009159800994c0048c96600266e252086030018acc004cdc7a450e626966726f73742d646b672d723100330034807000a2602066e18cdc02417e0266e012083010014810a29410164528202c371a00325980099b894831004dc6800c4cdc7a450e626966726f73742d646b672d723200330024807000629410154dd71803980b1baa0069bae30043016375400c91112cc00566002600800314a3130030014061159800acc004c01000a29462600600480c22b30013371e6600a90420080099802a41080200513371f300148132901c4005718375c601260346ea802a2941018452820308a50406037189000456600330013371e6eb8c00cc054dd50029bae30063015375400b4a14a2809a264b30013371e6eb8c004c058dd50034c0048cdc54c00528d20109b8d0015e480066eb8c010c058dd50034dd71803980b1baa0064888dca2cc004cdc3a400860306ea96600266e40008006298103d87980008acc004cdc7801000c530103d87a80008a6103d87b8000405c80ba266e29220116626966726f73742d6661756c742d65717569762d763100337146006002600600513371491116626966726f73742d6661756c742d65717569762d763100337146006004600600280b913322598009806998059bab30093018375401e01d1598009806cc004dd59804980c1baa00f9b94337140040031480012223322330010010023300f0030112259800800c00e2646644b30013372200e00515980099b8f0070028800c01901e44cc014014c08c01101e1bae301d001375a603c002603e00280f115980099b87480e0dc680144c028dc6800c528202c8a50405914a080b0dd71802980b1baa006375c6002602c6ea801a29410141180c180c980c980c980c980c980c800c52820268a50404d14a0809a29410131919912cc004c030c058dd500144c8cc8966002601e6eb4c06800e264b30013370e9002180d1baa001899192cc004c054c070dd500144c8c8c9660026046005132332259800980d80144c966002604e00313259800980e98121baa0018acc004c094dd5000c00e2c81322c8118c0980062c8128c08cdd5001c5660026030005132598009813800c4c966002603a60486ea8006264646644b3001302c003803c5902a1bae3029001375c60520046052002604a6ea80062c8118c0980062c8128c08cdd5001c59021204230203754002264b3001301a001899192cc004c09c00a0111640946eb8c094004c088dd5001c566002602e00315980098111baa003803459023459020204030203754004604400716408460420026042002603a6ea800a2c80d84c966002602460386ea8006264b30013371e00a03715980099b8f0060088acc004c040dc69bae3020301e37540031375c6040603c6ea80062c80e22c80e22c80e0c07cc074dd5000c5901b180f180e1baa001301d301b3754003164064601060346ea8c024c068dd50034590181bae3017001375c603460306ea800cc96600260360031301a0018b20323300b3756600c602e6ea8c018c05cdd500180a459015180b980a9baa3017301537546008602a6ea8004dd71802180a9baa0053298009800800cdd6980b980a9baa0059bac3004301537540189112cc004cdc4a40000051330030010028b202c1112cc004c03c0062603200519800801cc06800a66e012001001400c80a913259800980a000c4c96600266e1d2001375a602400315980099b8748004cc014dd5980198091baa009008898021b8d375c602200314a080822c8080c04c0062c8090cc010dd5980098081baa0070064038223232330010010042259800800c00e2646644b30013372200e00515980099b8f0070028800c01901244cc014014c05c0110121bae3011001375660240026026002809052f5bded8c060166ea8018dd7180618051baa003370e900145282010180400098021baa0088a4d13656400801" + }, + { + "title": "bitcoin/fault_verifier_round1.fault_verifier_round1.mint", + "compiledCode": "5931df010100229800aba2aba1aba0aab9faab9eaab9dab9a9bc2489608afe2380027a81ed2b0b956fdcc4fec6525e905e84902bb5b7fe4ba6124a6f1eb048ddba78b0ee898843fa8253bf7554181652302a4ed08232e0945a38ad56edb8b3e49daa7dfa7c43acc4dbcc381acff267e3be4b3768cfedb6f53c7472a0dc009bc248816093e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8009bbb488130c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009bae0024888888888896600264653001300c00198061806800cdc3a4001300c0024888966002600460186ea800e266446644b300130060018992cc004c058006264b30013008301237540031323232323298009bae301b001980e000cdd6980d802cdd7180d8024dd7180d801cdd7180d8012444444b30013022005899198008009bac30220062259800800c04626466006006604a0046eb8c08c00502145901f0c06c004c068004c064004c060004c04cdd5000c59011180a800c5901318089baa0088acc004c00c0062b3001301137540110028b20248b201e403c265300122329800800ccc01000c00a9000200222259800801440062653001004980d001cc8cdc01bad3017002003375c602a0028020c0600090164dc3a4081230143015301530153015001488966002601060246ea802a330013016301337540152301730180019180b980c180c000c8a6002003337026e34008006004b8c4dc6240009111119192cc004c8c96600266e252086030018acc004cdc7a450e626966726f73742d646b672d723100330054807000a2b30013371f3001002a4099480e10041bae3008301c3754013130113370c66e0120bf0133700904180800a408514a080d2294101a45282034371a0026eb8c014c068dd5003c66002466e1d2038371a0032300a371a0032301e301f301f301f301f301f001488966003300137586002603a6ea802a6eb8c024c074dd500545282444b3001003800c4c9660020030028acc004c09400626644b30013371e00401515980099b8f0010058acc004c02000a2601200314a0810a294102145282042375c60480086eb8c09000600481110221812001a04245660033001323322598009809180f9baa00289919912cc004c054dd69811801c4c96600266e1d2004302337540031323259800980d98129baa00289919192cc004c0b400a2646644b300130210028992cc004c0c4006264b30013023302d375400315980098171baa001801c5902f45902c1818000c5902e18161baa0038acc004c07800a264b300130310018992cc004c08cc0b4dd5000c4c8c8cc8966002606c0070078b2066375c60660026eb8c0cc008c0cc004c0b8dd5000c5902c1818000c5902e18161baa0038b205440a860526ea80044c96600260400031323259800981880140222c8170dd7181780098159baa0038acc004c0740062b3001302b37540070068b20588b205240a460526ea8008c0b000e2c8150c0ac004c0ac004c098dd50014590240992cc004c060c094dd5000c4c96600266e3c0140862b30013371e00c011159800980b1b8d375c6054604e6ea800626eb8c0a8c09cdd5000c59025459025459025181498131baa0018b2048302830253754002604e60486ea80062c8110c038c08cdd5180798119baa0068b2042375c60400026eb8c090c084dd5001992cc004c09400626048003164088660226eacc030c080dd5180618101baa00301a8b203c3021301e37546042603c6ea8c028c078dd50009bae300a301e375401665300130010019bad3021301e375401737586014603c6ea80492225980099b894800000a26600600200516407c22259800980a800c4c08c00a3300100398120014cdc024002002801901e4dd71804180e9baa00a9bae3020302130213021301d37540149112cc004c03cdc6801c56600266e1d208001371a00319800801cdc9001400576a8a50407914a080f1159800cc0048cdc319bca4a00029041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0748888966002602800913370c0049041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0746600200b3370c00600900499b810013370466e0c00c01000a00480290204888ca6002003004801a00222259800801440063300100398138014cc010dd69813001000a0064091223370c66e080080052082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e9112cc00400a297ae08acc004006297ae08998111ba73302230230023302230230014bd704c00400e60480053024001400c8109021488cdc319b800020014820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f83a6e1920009112cc00400a297ae08acc004006297ae08998111ba73302230230023302230230014bd704c00400e60480053024001400c8109021488c8cc00400400c896600200314bd7044cc08cdd418019bac30240013300200230250014089223370c66e040080052082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e911919800800801912cc004006297ae08998119ba83003375a604800266004004604a002811246eecc8ca600200348900a400080088896600266e1c004012200519800801ccdc599b8e00500100299b80480080050032040371a003374a90004dc524410101009119b86337020040029041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0748c084c088c088c088c088c088c088c0880064604260446044604460446044604400323021302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022001919b86337029041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df07000a4105010101c1fffffffff7bfcbff7f0349f79d550177d1091161cf330753bf9d534d3bdb7c1d222329800800c01200680088896600200510018cc00400e604e00533004375a604c004002801902448c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c0880064604260446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604400323021302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302200191810981118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c0880064604260446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460440032302130223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022001918109811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088006460426044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604400323021302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302200191810981118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088006460426044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460440032302130223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022001918109811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c0880064604260446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044003230213022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230220019181098111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088006460426044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460440032302130223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230220019181098111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088006460426044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044003230213022302230223022302230223022302230223022302230223022302230223022302230223022302230223022302230220019181098111811181118111811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088006460426044604460446044604460446044604460446044604460446044604460446044604460446044604460440032302130223022302230223022302230223022302230223022302230223022302230223022302230223022001918109811181118111811181118111811181118111811181118111811181118111811181118111811000c8c084c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088c088006460426044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604460446044604400323021302230223022302230223022302230223022302230223022302230223022302230220019805980e9baa00a8a50488888888888888888888888888888888888888888888888888888888a60026070071303503591194c0040060070024004444b30013371000290004520008acc004c14000629001456600260a066e1800520048cc00400e66076004005337060029002200689981d8014c00400e660760040053370666e0120010014801100320b2416482ca60640652323305a37506076002660b4605e660b46ea4cc108dd7182d982c1baa00248100cc168dd499b8a375c608860b06ea8008c0b80052f5c097ae03304048100dd7182d182b9baa001919191982d9ba833037303c0013370c66e08c0f0dca000a41f9ffffff7f010101011181690101fb6f13c555ff135feddf3f6399f35b83c559678b4b04069041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df071982d98181982d982e182c9baa0033305b375200497ae04bd701b94001337146eb8c10cc15cdd5000a4410100009191982d1ba90013305a302f3305a3752660846eb8c16cc160dd5001240c0660b46ea4cdc51bae304430583754004605c00297ae04bd7019820240c06eb8c168c15cdd5000c88c0bccc168c16cc160dd50009982d1ba9337146eb8c110c160dd500098174c00528520408012f2497ae09118179982d1ba7323322330020020012259800800c400e2660ba60bc0026600400460be00282e0dd6182e182c9baa003375860b660b06ea80052f5c122302f3305a302f3305a374e660b4605e660b49810101003305a375200497ae04bd7025eb80cc168dd3800a5eb82453001002a4005223303a0013303400300240a1330583750607207a660b06ea0c0e4dd71821182b1baa0434bd702444444444444664466453001222232330463301430073304400223304600600100223304c3304c375a60de0020046eb4c1bcc1c0004cc128cc0fc00d20020029111111919198381838800998381ba83304e002375a60e260e400297ae032329800800c0229001530105d8799f80ff00982624105010101c1fffffffff7bfcbff7f0349f79d550177d1091161cf330753bf9d534d3bdb7c1c8008888896600200913307500233075375000297ae08994c00401a60f000b3305400400b9918261983b9ba7329800800cdd6183c983b1baa307930763754007375860f260ec6ea80150011112cc00400a200313298008024c1f400e660f660a0660f66ea0cc164014dd6983e183c9baa0013307b30653079375400297ae0002401060f600483c92f5c0660a801000933052002330540043300f375860c060e86ea800401d006183b00220e859800803c52f5c11598009838803c4cc1bd3010101004bd7044c8cc124cc054004c028cc1240048dd6983918398009198279bad3072375860e40026eb4c1c8c1cc004c8cc004004020896600200314bd7044cc1c4dd3994c00402a660e4981010100330724c10101004bd70488cc896600266e1c0100162660ec6ea0008cc1d8dd4000a5eb822660ec6ea0cc150008cc138030010cc1d8dd41982a0009982700280225eb810721bad3075001375a60ea60ec0028288dd69839000998010011839800a0e041b88370cc130008006444466086646600200200644b30013371000600314bd7044cc1b8dd40009980100119b804800800506a14c0040160094800a0028041222598008044052264b300100180ac56600260dc00313298009bad3018306b37540039800a418d9be311ed7fa7cf1b77bf138f437dd93f05bf3735ddfb213d9d2d5f8d55bdb57953e756034820367be8e879f0703abe60b2be2fb86d7cec37b6b7b534757bfc37e53abe2f32f07533ea0166eb4c060c1acdd5000d200240219800a418d9be311ed7fa7cf1b77bf138f437dd93f05bf3735ddfb213d9d2d5f8d55bdb57953e756034820367be8e879f0703abe60b2be2fb86d7cec37b6b7b534757bfc37e53abe2f32f07533ea0166eb4c060c1acdd5000d200440219800a418d9be311ed7fa7cf1b77bf138f437dd93f05bf3735ddfb213d9d2d5f8d55bdb57953e756034820367be8e879f0703abe60b2be2fb86d7cec37b6b7b534757bfc37e53abe2f32f07533ea0166eb4c060c1acdd5000d200640219800a418d9be311ed7fa7cf1b77bf138f437dd93f05bf3735ddfb213d9d2d5f8d55bdb57953e756034820367be8e879f0703abe60b2be2fb86d7cec37b6b7b534757bfc37e53abe2f32f07533ea0166eb4c060c1acdd5000d200d40219800a418d9be311ed7fa7cf1b77bf138f437dd93f05bf3735ddfb213d9d2d5f8d55bdb57953e756034820367be8e879f0703abe60b2be2fb86d7cec37b6b7b534757bfc37e53abe2f32f07533ea0166eb4c060c1acdd5000d20014020911111194c0066002660e86ea001d2f5c13307433013375c60ba60e46ea8020cc1d0c0a8c1c8dd500425eb80cc1d0cc04cdd7182b18391baa00833074302b3072375401097ae0330743301348930e42f710d3ca274922f6e2574ac100109980081796aa992c8fca4d0d44c4628b02c5828c2796ec48ec0c17eade800c6ad0033074302c3072375401097ae03307433013489304a1dfd9085c2a3b9ae3120570c50a50352132f17fcd25bae541c7cbcca3c567f8d33c98ae5f98940241f95c559c4d2a20033074302d3072375401097ae033074330134893009f025e821202127a6562426d87ec3c1620a571747217afad01a096110e7f87f311a4cde848c85d9eaf64a92413755b40033074302e3072375401097ae03307433013489300f8c041330e49e4b394e9e462fe69856025931606525ab2212f85c87b18c9f7292062231b939079557ec84c92e3f2e820033074302f3072375401097ae0330743301348930d5c8b945c37bb5b6f95688579d313791f5423d8fe49c9abcf01d822a447a1ba2b9ce42382d40beadeefbf9e8f4d90fb1003307430303072375401097ae033074330134893068618ff1b1e118cf8250de7b730c532a308e8ba126cd4f22254e0477a2c91387a4b37fd53e025b9a2e14e5098fa6fa86003307430313072375401097ae0330743301348930994aab9c1d607760e54b000814151fde7d88db704ed013fdbd4033a80ab129ba2307315de84a35c306209f2968ef8fa9003307430323072375401097ae0330743301348930fe1974ce73e65bcaeef9353b95c199a03c41272b9b3bcc99fe6bf2602f0a9932d923946d03d15c2963d7816aacce5882003307430333072375401097ae0330743301348930b099a02300321b95323e4ce48e0d3daafeb72f126034f1f6b73a9a566991222f2cccf2a2f5c824f802ac52839bf5ef99003307430343072375401097ae03307430493307432304a33075374e660ea6094660ea9801010100330753076307730773077307730773077307730773077307730773077307730773073375401297ae033075304a330753750002660ea60ec60ee60ee60ee60ee60ee60ee60ee60ee60ee60ee60ee60ee60ee60ee60ee60e66ea80252f5c0660ea6094660ea6ea0cc06c005200433075307630773077307730773077307730773077307730773077307730773077307730773073375401297ae04bd7025eb80cc068dd6980f98391baa00848202020010cc1d0dd39983a1ba832323232323232323259800983f800c4ca6002660ac90011982d0009982d1982d1982d1982d1982d1bad307f008375a60fe00e6eb4c1fc018dd6983f8029bad307f004375a60fe0073301701b98009bad3029307c375402500aa4105210101c1ff03211bf9ffc95b05b51d7763edfb6d212377dd25d537291901e70d2ddb7c1d9800a418d9be311ed7fa7cf1b77bf138f437dd93f05bf3735ddfb213d9d2d5f8d55bdb57953e756034820367be8e879f0703abe60b2be2fb86d7cec37b6b7b534757bfc37e53abe2f32f07533ea016900052002405080b26eb4c1fc0092223305f980099840809ba83305f375a607660fe6ea8054cc174cc174dd69817183f9baa0153305f375a605e60fe6ea8054dd69818183f9baa0153050375a606260fe6ea8054cc20404dd41982f9bad303c307f375402a660ba660ba6eb4c0c8c1fcdd500a9982f9bad3033307f375402a6eb4c0d0c1fcdd500a98281bad3035307f375402a66102026ea0cc17c004cc1652002375a608860fe6ea8054cc20404dd41982f8021982c9982f9bad3049307f375402a6eb4c124c1fcdd500a9bad3049307f375402a66102026ea0cc17c004cc164dd69823983f9baa015375a608660fe6ea8054cc20404dd41982f8009982c9bad3049307f375402a6eb4c118c1fcdd500a99840809ba83305f003330593305f3305f375a608a60fe6ea8054cc174cc174dd6981c983f9baa0153305f375a60a460fe6ea8054dd6981e983f9baa015375a60a660fe6ea8054cc174cc174dd69817183f9baa0153305f375a60a460fe6ea8054dd6981f183f9baa015375a60a660fe6ea8054cc17ccc17cdd69822183f9baa0153305d3305d375a607260fe6ea8054cc17cdd69829183f9baa015375a605860fe6ea8054dd69829983f9baa0153305d3305d375a605c60fe6ea8054cc17ccc17cdd69829183f9baa015375a605860fe6ea805520aea78c90ab9e9a88d881e089d4f19ba4a0d99786e0aefdd4e6aa9e84dfea90a095b49a8601375a60a660fe6ea8054cc20404dd41982f8019982c9982f9982f9bad3048307f375402a660ba660ba6eb4c0c8c1fcdd500a9982f9bad3052307f375402a6eb4c0fcc1fcdd500a9bad3053307f375402a660ba660ba6eb4c0dcc1fcdd500a9982f9bad3052307f375402a6eb4c100c1fcdd500a9bad3053307f375402a660be660be6eb4c11cc1fcdd500a9982e9982e9bad3032307f375402a660be660be6eb4c148c1fcdd500a9bad302c307f375402a6604e905753c64855cf4d446c40f044ea78cdd2506ccbc370577eea73554f426ff548504ada4d4300a40086eb4c14cc1fcdd500a9982e9982e9bad3037307f375402a660be660be6eb4c148c1fcdd500a9bad302c307f375402a6604e905753c64855cf4d446c40f044ea78cdd2506ccbc370577eea73554f426ff548504ada4d4300a400c6eb4c14cc1fcdd500a99840809ba83305f003330593305f375a609460fe6ea8054cc174cc174008cc17cdd69829183f9baa015375a608260fe6ea8054dd69829983f9baa0153305f375a609260fe6ea8054cc174cc174008cc17ccc17cdd69829183f9baa015375a605860fe6ea8054cc09d20aea78c90ab9e9a88d881e089d4f19ba4a0d99786e0aefdd4e6aa9e84dfea90a095b49a860148020dd69829983f9baa01533081013750660be002660b290011bad304b307f375402a66102026ea0cc17c010cc164cc17cdd69825983f9baa015375a609660fe6ea8054dd69825983f9baa01533081013750660be006660b2660be660be6eb4c130c1fcdd500a9982e9bad304e307f375402a6eb4c148c1fcdd500a9982e9bad3038307f375402a6eb4c14cc1fcdd500a9982f9982f9bad304b307f375402a660ba6eb4c0dcc1fcdd500a9bad3052307f375402a660ba6eb4c0e8c1fcdd500a9bad3053307f375402a66102026ea0cc17c004cc164dd69827183f9baa015375a607060fe6ea8054cc20404dd41982f9982f8019982c9bad304e307f375402a6eb4c0e0c1fcdd500a9982c9bad304e307f375402a6eb4c134c1fcdd500aa5eb8260b89041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df07488cc17ccc184004dd69842009842809842809842809842809842809842809842809842809842809842809842809842809842809840809baa017002413c603a660a801a90010dd6983f00445907c183f000983e800983e000983d800983d000983c800983c000cc004dd6981018399baa009800d2082908080e0ff81908dfcffe4ad82da8ebbb1f6fdb69091bbee92ea9b948c80f38696edbe0ecc00520c6cdf188f6bfd3e78dbbdf89c7a1beec9f82df9b9aeefd909ece96afc6aadedabca9f3ab01a4101b3df4743cf8381d5f30595f17dc36be761bdb5bda9a3abdfe1bf29d5f1799783a99f500b48036900020164034660346eb4c07cc1c8dd50042410101000897ae04bd701983a198099bae307530763076307630763076307630763076307630763076307630723754010660e860ea60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60ec60e46ea80212f5c097ae09bad302030723754011375a605260e46ea80226eb4c0d4c1c8dd50044cc148cc048cc1d0dd40031983a1ba8005330743750008660e86ea000ccc1d0dd400125eb80dd6981018391baa008001402d98009983a1ba800333074375000e660e86ea00192f5c13307433013375c60ea60ec60ec60ec60ec60ec60ec60ec60ec60e46ea8020cc1d0c0d8c1c8dd50041983a181b98391baa0083307430383072375401097ae03307433013375c60ea60ec60ec60ec60ec60ec60ec60ec60ec60ec60e46ea8020cc1d0c0e4c1c8dd50041983a181d18391baa00833074303b3072375401097ae04bd704dd6981018391baa0089bad3029307237540113301a375a606a60e46ea8021200499829198091983a1ba8005330743750008660e86ea00092f5c06eb4c080c1c8dd5004000a016cc004cc1d0dd40039983a1ba80064bd704cc1d0cc04cdd7183a983b183b183b183b183b183b183b183b183b183b18391baa00833074303c30723754010660e8607a60e46ea80212f5c0660e8660266eb8c1d4c1d8c1d8c1d8c1d8c1d8c1d8c1d8c1d8c1d8c1d8c1d8c1c8dd50041983a181f18391baa00833074303f3072375401097ae04bd704dd6981018391baa0089bad3029307237540113301a375a606a60e46ea8021200699829198091983a1ba8005330743750008660e86ea000ccc1d0dd400125eb80dd6981018391baa008001402d98009983a1ba800233074375000e97ae09983a198099bae306030723754010660e8608060e46ea8020cc1d0c104c1c8dd500425eb812f5c1375a604060e46ea80226eb4c0a4c1c8dd50044cc068dd6981a98391baa00848022660a466024660e86ea0018cc1d0dd40029983a1ba800433074375000697ae0375a604060e46ea802000500b66002660e86ea001ccc1d0dd40031983a1ba800533074375000897ae09983a198099bae307530723754010660e8604260e46ea8020cc1d0c088c1c8dd50041983a181198391baa0083307430243072375401097ae03307433013375c60bc60e46ea8020cc1d0c094c1c8dd50041983a181318391baa00833074302730723754010660e8605060e46ea80212f5c097ae09bad302030723754011375a605260e46ea8022900152002402c9111119bc633788609e6eb8c124c1dcdd500683a19bc4329800800cdd6183d983c1baa3301a329800800ccc1ecc1f000ccc1ecc1f001ccc1ecc1f0018cc1ecc1f0014cc1ecc1f00112f5c14c0105d8799f80ff004004444b30010028800c66002007307f0029980e800983f001200641f0609e660f46e9ccc1e8c13ccc1e8dd41824cc004cc1e8c1ecc1f0008cc1e8c1ecc1f0018cc1e8c1ecc1f0014cc1e8c1ecc1f0010cc1e8c1ecc1f000d2f5c130554820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f83a44660b00020048240cc1e9301325830bbc622db0af03afbef1a7af93fe8556c58ac1b173f3a4ea105b974974f8c68c30faca94f8c63952694d79731a7d3f197004bd701983d18279983d1ba83049330183307a375001a660f46ea0030cc1e8dd40059983d1ba800a4bd701bad30263078375401c660f460f660f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f860f06ea80392f5c0660f4609e660f4604c60f06ea8038cc1e8c128c1e0dd500725eb812f5c097ae0839a002222598008014400633001003983f0014c8cddb00119bb8375a60fc60f66ea8004c14cdd71833983d9baa001307d002400c83d81cc601e66022660e66ea0008cc1ccdd4000a5eb80dd6980f98389baa007191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919183b998510098518081b198510098518081a998510098518081a19851009851808199985100985180819198510098518081899851009851808181985100985180817998510098518081719851009851808169985100985180816198510098518081599851009851808151985100985180814998510098518081419851009851808139985100985180813198510098518081299851009851808121985100985180811998510098518081119851009851808109985100985180810198510098518080f998510098518080f198510098518080e998510098518080e198510098518080d998510098518080d198510098518080c998510098518080c198510098518080b998510098518080b198510098518080a998510098518080a198510098518080999851009851808091985100985180808998510098518080819851009851808079985100985180807198510098518080699851009851808061985100985180805998510098518080519851009851808049985100985180804198510098518080399851009851808031985100985180802998510098518080219851009851808019985100985180801198510098518080099851009851809822185180985200800a5eb80c110c28804c28c04004c108c28404c28804004c108c28004c28404004c104c27c04c28004004c104c27804c27c04004c100c27404c27804004c0fcc27004c27404004c0f8c26c04c27004004c0f4c26804c26c04004c0f0c26404c26804004c0ecc26004c26404004c0e8c25c04c26004004c0e4c25804c25c04004c0e0c25404c25804004c0dcc25004c25404004c0d8c24c04c25004004c0d4c24804c24c04004c0d0c24404c24804004c0ccc24004c24404004c0c8c23c04c24004004c0c4c23804c23c04004c0c0c23404c23804004c0bcc23004c23404004c0b8c22c04c23004004c0b4c22804c22c04004c0b0c22404c22804004c0acc22004c22404004c0a8c21c04c22004004c0a4c21804c21c04004c0a0c21404c21804004c09cc21004c21404004c098c20c04c21004004c094c20804c20c04004c090c20404c20804004c08cc20004c20404004c088c1fcc20004004c080c1f8c1fc004c078c1f4c1f8004c074c1f0c1f4004c070c1ecc1f0004c070c1e8c1ec004c068c1e4c1e8004c064c1e0c1e4004c060c1dcc1e0004c05cc1d8c1dc004c058c1d4c1d8004c058c1d0c1d4004c054c1ccc1d0004c04cc1c8c1cc004c048c1c4c1c8004c048c1c0c1c4004c040c1bcc1c0004c03cc1b8c1bc004c038ca600200300a998072416d754f0fef115f2369c33bf155bb639f270b33612bb3094b61cb4fdbc145ef4f89b5d3c2186084660da02e660da98010140004bd70200222259800801440063300100398388014cc040dd69838001000a00641b901541ac8358c1b402106a096600200314bd7044c8c8cc1a4c1a8c1ac004dd61835000994c0040066602060d60053001003a5eb8244660d66ea00080050484cc1a5301018000330693750600a6eb4c1a80092f5c080088896600200510018cc00400e60da00533223306d374e660da6ea0cc12c004dd698370011bac306e0033306d3750660960026eb4c1b8c1bc0092f5c06eb0c1b0008dd698361836800a00641a930013069001998339834000a5eb8244b30010018b44cc1a4dd4198238011bad306a00100141a0823106611194c0040066602000600530444820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f8390011112cc00400a200319800801cc1b400a6466090004660946eb4c1b4004dd6983698370009bac306c002400c83508cdc34c0040069041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0752002a400080692082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e22225980099b880014800226608c6601c006b300133710002900044cdc0a4000003100141900051330463300e004001002419044c96600260206601c6eacc030c078dd5009008c5660026021300137566018603c6ea804a6e50cdc5000802c520004888cc88cc004004008cc04800c050896600200300389919912cc004cdc8803801456600266e3c01c00a20030064091133005005302a00440906eb8c08c004dd698120009813000a04845660026008003130030058a50407114a080e2294101c1bae3009301d375401514a080da294101b4528203645282030329800800ccdc02407e6e3400690202004375c600860326ea8018888cc010004cc01400c00913259800980c000c4c96600266e1d2001375a602a00315980099b8748004cc014dd59801980a9baa009008898021b8d375c602800314a0809a2c8098c05c0062c80a8cc010dd5980098099baa0070064044223232330010010042259800800c00e2646644b30013372200e00515980099b8f0070028800c01901544cc014014c06c0110151bae30140013756602a002602e00280a852f5bded8c0601c6ea8018dd7180818069baa003370e900145282016180600098039baa00c8a4d1365640141" + }, + { + "title": "bitcoin/fault_verifier_round2.fault_verifier_round2.mint", + "compiledCode": "593537010100229800aba2aba1aba0aab9faab9eaab9dab9a9bc2489608afe2380027a81ed2b0b956fdcc4fec6525e905e84902bb5b7fe4ba6124a6f1eb048ddba78b0ee898843fa8253bf7554181652302a4ed08232e0945a38ad56edb8b3e49daa7dfa7c43acc4dbcc381acff267e3be4b3768cfedb6f53c7472a0dc009bc248816093e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8009bbb488130c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009bae0024888888888896600264653001300c00198061806800cdc3a4001300c0024888966002600460186ea800e266446644b300130060018992cc004c058006264b300130083012375400313232323232323232323298009bae30200019810800cdd698100054dd71810004cdd718100044dd71810003cdd718100034dd71810002cdd698100024dd71810001cdd71810001244444444444b3001302c00a899198008009bac302c00b2259800800c06e26466006006605e0046eb8c0b400502b4590290c080004c07c004c078004c074004c070004c06c004c068004c064004c060004c04cdd5000c59011180a800c5901318089baa0088acc004c00c0062b3001301137540110028b20248b201e403c265300122329800800ccc01000c00a9000200222259800801440062653001004980d001cc8cdc01bad3017002003375c602a0028020c0600090164dc3a4081230143015301530153015001488966002601060246ea802a330013016301337540152301730180019180b980c180c000c8a6002003337026e34008006004b8c4dc624001230173018301830183018301830180019ba5480024602e603060306030603060300029111111119194c004dd71801980e9baa0019919912cc004c048c07cdd500144c8cc8966002602a6eb4c08c00e264b30013370e900218119baa001899192cc004c06cc094dd500144c8c8c966002605a005132332259800981080144c966002606200313259800981198169baa0018acc004c0b8dd5000c00e2c817a2c8160c0c00062c8170c0b0dd5001c566002603c005132598009818800c4c9660026046605a6ea8006264646644b30013036003803c590331bae3033001375c60660046066002605c6ea80062c8160c0c00062c8170c0b0dd5001c5902a205430293754002264b30013020001899192cc004c0c400a0111640b86eb8c0bc004c0acdd5001c566002603a00315980098159baa00380345902c45902920523029375400460580071640a860560026056002604c6ea800a2c81204c9660026030604a6ea8006264b30013371e00a04315980099b8f0060088acc004c058dc69bae302a302737540031375c6054604e6ea80062c812a2c812a2c8128c0a4c098dd5000c59024181418129baa001302730243754003164088601c60466ea8c03cc08cdd50034590211bae3020001375c604860426ea800cc966002604a003130240018b2044330113756601860406ea8c030c080dd500180d45901e1810980f1baa3021301e37546014603c6ea8004dd71805180f1baa00b3298009800800cdd69810980f1baa00b9bac300a301e37540249112cc004cdc4a40000051330030010028b203e1112cc004c0540062604600519800801cc09000a66e012001001400c80f253001001a4099480e10032444b300132325980099b89482180c0062b30013371e9110e626966726f73742d646b672d7231003300b4807000a2b30013371e60060046eb8c038c088dd5007c4c05ccdc319b80482fc04cdc024106020029021452820408a50408114a08100dc68009bae300b3020375401b15980099192cc004cdc4a419c0600315980099b8f4890e626966726f73742d646b672d7232003300b4807000a2b30013371e60060046eb8c038c088dd5007c4c05ccdc319b804820c0400520ca028a50408114a0810229410201b8d001375c601c60406ea80363300123370e901c1b8d001918081b8d001918121812981298129812981298129812981298129812800a444b300198009bac300130233754021375c601e60466ea8042294122259800801c006264b300100180145660026056003133225980099b8f00200c8acc004cdc7800802c5660026010005130090018a50409d14a0813a29410271bae302a004375c605400300240a08140c0a800d02723300123027302830283028001918139814181418141814181418141814000c8c09cc0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a00052225980099912cc004c05cdc68014566002602e6e340062b30013371e6e50008dd7180b18141baa00c8acc004cdc7cc005284dd7180298141baa00c8012f34003159800980b9b8d001899baf4c0103d87980005980099b9000148920fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141008a6103d87980008acc004cdc7800a44120fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141008a6103d87a80008a6103d87b80004098813229410264528204c8a50409914a0813229410261bae3002302637540266eb8c004c098dd5009c4c96600330010099bae301230273754029375c6008604e6ea8051001456600330010099bae301530273754029375c601a604e6ea8051001456600330012302b302c302c302c302c302c302c302c302c302c001919b86337949400052082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e911112cc004c078012266e180092082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e8cc00401666e1800c0120093370200266e08cdc180180200140090052054911194c0040060090034004444b30010028800c660020073031002998021bad3030002001400c81724466e18cdc1001000a4105010101c1fffffffff7bfcbff7f0349f79d550177d1091161cf330753bf9d534d3bdb7c1d22259800801452f5c1159800800c52f5c113302c374e66058605a00466058605a00297ae09800801cc0b800a605c002801902b20569119b86337000040029041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df074dc32400122259800801452f5c1159800800c52f5c113302c374e66058605a00466058605a00297ae09800801cc0b800a605c002801902b2056911919800800801912cc004006297ae08998169ba830033758605c00266004004605e00281624466e18cdc0801000a4105010101c1fffffffff7bfcbff7f0349f79d550177d1091161cf330753bf9d534d3bdb7c1d2232330010010032259800800c52f5c113302d375060066eb4c0b8004cc008008c0bc00502c48ddd99194c004006910100a400080088896600266e1c004012200519800801ccdc599b8e00500100299b80480080050032054371a003371491010101009119b86337020040029041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0748c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0006466e18cdc0a4105010101c1fffffffff7bfcbff7f0349f79d550177d1091161cf330753bf9d534d3bdb7c1c0029041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df074888ca6002003004801a00222259800801440063300100398188014cc010dd69818001000a00640b92230103302b374e6466446600400400244b30010018801c4cc0b8c0bc004cc008008c0c000502d1bac302d302a37540066eb0c0b0c0a4dd5000a5eb8246056605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c001918159816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b000646056605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c0019181598161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0006460566058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c001918159816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0006460566058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c0019181598161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0006460566058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c00191815981618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b00064605660586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c001918159816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b000646056605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c00191815981618161816181618161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b00064605660586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c0019181598161816181618161816181618161816181618161816181618161816181618161816181618161816000c8c0acc0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0c0b0006460566058605860586058605860586058605860586058605860586058605860586058605860580032230103302b30103302b374e660566020660569810101003302b375200497ae04bd7025eb80cc0acdd3800a5eb8246056605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860586058605860580032302b302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c0018a5048888888888888888888888888888888888888888888888888888888a6002606c06d303303391194c0040060070024004444b30013371000290004520008acc004c16400629001456600260b266e1800520048cc00400e66072004005337060029002200689981c8014c00400e660720040053370666e0120010014801100320c44188831260600612323306337506072002660c66090660c66ea4cc12cdd7183218309baa00248100cc18cdd499b8a375c609a60c26ea8008c0b40052f5c097ae03304948100dd7183198301baa00191919198321ba833035303a0013370c66e08c0e8dca000a41f9ffffff7f010101011181690101fb6f13c555ff135feddf3f6399f35b83c559678b4b04069041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0719832182499832183298311baa00333064375200497ae04bd701b94001337146eb8c130c180dd5000a441010000919198319ba9001330633048330633752660966eb8c190c184dd5001240c0660c66ea4cdc51bae304d30613754004605a00297ae04bd7019824a40c06eb8c18cc180dd5000c88c120cc18cc190c184dd5000998319ba9337146eb8c134c184dd50009816cc00528520408012f2497ae0914c00400a9001488cc0e0004cc0c800c0090294c0e0c17cdd50264cc184dd4181b821198309ba83037375c609660be6ea81312f5c091111111111199119914c0048888c8cc10ccc04cc01ccc1040088cc10c0180040088cc124cc124dd6983b8008011bad30773078001330473303d0034800800a4444446464660f060f2002660f06ea0cc12c008dd6983c983d000a5eb80c8ca6002003008a40054c0105d8799f80ff009824a4105010101c1fffffffff7bfcbff7f0349f79d550177d1091161cf330753bf9d534d3bdb7c1c8008888896600200913307d0023307d375000297ae08994c00401a61000200b3305100400b9918321983f9ba7329800800cdd6184080983f1baa308101307e3754007375861020260fc6ea80150011112cc00400a200313298008024c2140400e661060260d066106026ea0cc158014dd69842009840809baa0013308301306d308101375400297ae000240106106020048408092f5c0660a20100093304f002330510043300f375860d060f86ea800401d006183f00220f859800803c52f5c1159800983c803c4cc1dd3010101004bd7044c8cc118cc050004c028cc1180048dd6983d183d8009198261bad307a375860f40026eb4c1e8c1ec004c8cc004004020896600200314bd7044cc1e4dd3994c00402a660f49810101003307a4c10101004bd70488cc896600266e1c0100162660fc6ea0008cc1f8dd4000a5eb822660fc6ea0cc144008cc12c030010cc1f8dd4198288009982580280225eb8107a1bad307d001375a60fa60fc0028270dd6983d00099801001183d800a0f041d883b0cc124008006444466080646600200200644b30013371000600314bd7044cc1d8dd40009980100119b804800800507214c0040160094800a002804122259800804404e264b300100180a456600260ec00313298009bad3016307337540039800a41eda767df633f1b85bdeb0fc93399bf475fdd0b77d3e1e1f5c57b532dc1a7796195b505a60b4829b1f23b692824ae6973707abeabb4322c6373f5f43dea38f06fe0e1e968203d29feee26c0a6eb4c058c1ccdd5000d200240219800a41eda767df633f1b85bdeb0fc93399bf475fdd0b77d3e1e1f5c57b532dc1a7796195b505a60b4829b1f23b692824ae6973707abeabb4322c6373f5f43dea38f06fe0e1e968203d29feee26c0a6eb4c058c1ccdd5000d200440219800a41eda767df633f1b85bdeb0fc93399bf475fdd0b77d3e1e1f5c57b532dc1a7796195b505a60b4829b1f23b692824ae6973707abeabb4322c6373f5f43dea38f06fe0e1e968203d29feee26c0a6eb4c058c1ccdd5000d200640219800a41eda767df633f1b85bdeb0fc93399bf475fdd0b77d3e1e1f5c57b532dc1a7796195b505a60b4829b1f23b692824ae6973707abeabb4322c6373f5f43dea38f06fe0e1e968203d29feee26c0a6eb4c058c1ccdd5000d200d40219800a41eda767df633f1b85bdeb0fc93399bf475fdd0b77d3e1e1f5c57b532dc1a7796195b505a60b4829b1f23b692824ae6973707abeabb4322c6373f5f43dea38f06fe0e1e968203d29feee26c0a6eb4c058c1ccdd5000d20014020911111194c0066002660f86ea001d2f5c13307c3301f375c60ca60f46ea8020cc1f0c0a4c1e8dd500425eb80cc1f0cc07cdd71830183d1baa0083307c302a307a375401097ae03307c3301f489302f87bc23d4821232bc7a6b88902ea0addbc9d2bd1bab3000f61a0d08019184f628859ebfec469a2945bbf09472dcefa4003307c302b307a375401097ae03307c3301f48930d11ca0417f5686a664b311bd33cefa06fb2299390162cd2920a7284e74174d5b1bb0e6fb6ad7af12da91cdfb900dbfa7003307c302c307a375401097ae03307c3301f489304b47c56fec6465007aab949bf1e8526e94ccac912f37bcccb3f27992798862ae5dde262d8ef3b25f3d40499d1bd55d93003307c302d307a375401097ae03307c3301f4893049dc441ae13a562daf779e579c171281ad3f1e9f2eee210b6c833320229f2d7460ea54ef1a2a385b873fa6fba4fa3e96003307c302e307a375401097ae03307c3301f4893040b5e2ba5f26ec5bf47f0fd436573392594bb6b4a0a37fe63e2519c8abb4c9fb7ef6b263ace86f49857933f51c4bc185003307c302f307a375401097ae03307c3301f489306e3e65c8dd480c7ccea28bf72639e8e39c058382f0b0206e037dd7bc70d63d6db63a59c65aed85199ee908c25733f482003307c3030307a375401097ae03307c3301f489301fbf0ec3845b487a951b2b9de454683ca8ac13f66a8c0c3c5707bd96838afe14cb6bd0510a63e15f7f51fcd0f04fe886003307c3031307a375401097ae03307c3301f4893092ecf7324e43b1c9fe897f5b5a9dee6dc59d4b35352de9911196a379216330bff5473d861746c955c77e6410d6799d90003307c3032307a375401097ae03307c3301f48930ceb90f8c15be9597dc39d45f3618d146f4c7f4334eaf52381c69d33acc8df947cde54cd6157a3f785d72fe1644c11691003307c3033307a375401097ae03307c30613307c3230623307d374e660fa60c4660fa98010101003307d307e307f307f307f307f307f307f307f307f307f307f307f307f307f307f307b375401297ae03307d30623307d3750002660fa60fc60fe60fe60fe60fe60fe60fe60fe60fe60fe60fe60fe60fe60fe60fe60fe60f66ea80252f5c0660fa60c4660fa6ea0cc06800520043307d307e307f307f307f307f307f307f307f307f307f307f307f307f307f307f307f307f307b375401297ae04bd7025eb80cc064dd6980e983d1baa008482020080cc1f0dd39983e1ba832323232323232323259800984380800c4ca6002660a690011982b8009982b9982b9982b9982b9982b9bad308701008375a610e0200e6eb4c21c04018dd69843808029bad308701004375a610e020073301701b98009bad3027308401375402500aa4105010501c1ff3f01a5fbbfb3bfcb139ff1edcdb3f5cf93732d3f3f1bb959c97f5f53d97c1d9800a41eda767df633f1b85bdeb0fc93399bf475fdd0b77d3e1e1f5c57b532dc1a7796195b505a60b4829b1f23b692824ae6973707abeabb4322c6373f5f43dea38f06fe0e1e968203d29feee26c0a900052002405080b26eb4c21c040092223305c980099844809ba83305c375a6074610e026ea8054cc168cc168dd698169843809baa0153305c375a605c610e026ea8054dd698179843809baa0153050375a6060610e026ea8054cc22404dd41982e1bad303b308701375402a660b4660b46eb4c0c4c21c04dd500a9982e1bad3032308701375402a6eb4c0ccc21c04dd500a98281bad3034308701375402a66112026ea0cc170004cc1592002375a6086610e026ea8054cc22404dd41982e0021982b1982e1bad3048308701375402a6eb4c120c21c04dd500a9bad3048308701375402a66112026ea0cc170004cc158dd698231843809baa015375a6084610e026ea8054cc22404dd41982e0009982b1bad3048308701375402a6eb4c114c21c04dd500a99844809ba83305c003330563305c3305c375a6088610e026ea8054cc168cc168dd6981c1843809baa0153305c375a60de610e026ea8054dd6981e1843809baa015375a60c6610e026ea8054cc168cc168dd698169843809baa0153305c375a60de610e026ea8054dd6981e9843809baa015375a60c6610e026ea8054cc170cc170dd698219843809baa0153305a3305a375a6070610e026ea8054cc170dd698379843809baa015375a6054610e026ea8054dd698319843809baa0153305a3305a375a605a610e026ea8054cc170cc170dd698379843809baa015375a6054610e026ea805520aea78c90ab9e9a88d881e089d4f19ba4a0d99786e0aefdd4e6aa9e84dfea90a095b49a8601375a60c6610e026ea8054cc22404dd41982e0019982b1982e1982e1bad3047308701375402a660b4660b46eb4c0c4c21c04dd500a9982e1bad306f308701375402a6eb4c0f8c21c04dd500a9bad3063308701375402a660b4660b46eb4c0d8c21c04dd500a9982e1bad306f308701375402a6eb4c0fcc21c04dd500a9bad3063308701375402a660b8660b86eb4c118c21c04dd500a9982d1982d1bad3031308701375402a660b8660b86eb4c1bcc21c04dd500a9bad302a308701375402a6604c905753c64855cf4d446c40f044ea78cdd2506ccbc370577eea73554f426ff548504ada4d4300a40086eb4c18cc21c04dd500a9982d1982d1bad3036308701375402a660b8660b86eb4c1bcc21c04dd500a9bad302a308701375402a6604c905753c64855cf4d446c40f044ea78cdd2506ccbc370577eea73554f426ff548504ada4d4300a400c6eb4c18cc21c04dd500a99844809ba83305c003330563305c375a6092610e026ea8054cc168cc168008cc170dd698379843809baa015375a6080610e026ea8054dd698319843809baa0153305c375a6090610e026ea8054cc168cc168008cc170cc170dd698379843809baa015375a6054610e026ea8054cc09920aea78c90ab9e9a88d881e089d4f19ba4a0d99786e0aefdd4e6aa9e84dfea90a095b49a860148020dd698319843809baa01533089013750660b8002660ac90011bad304a308701375402a66112026ea0cc170010cc158cc170dd698251843809baa015375a6094610e026ea8054dd698251843809baa01533089013750660b8006660ac660b8660b86eb4c12cc21c04dd500a9982d1bad304d308701375402a6eb4c1bcc21c04dd500a9982d1bad3037308701375402a6eb4c18cc21c04dd500a9982e1982e1bad304a308701375402a660b46eb4c0d8c21c04dd500a9bad306f308701375402a660b46eb4c0e4c21c04dd500a9bad3063308701375402a66112026ea0cc170004cc158dd698269843809baa015375a606e610e026ea8054cc22404dd41982e1982e0019982b1bad304d308701375402a6eb4c0dcc21c04dd500a9982b1bad304d308701375402a6eb4c130c21c04dd500aa5eb8260b29041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df07488cc170cc178004dd69846009846809846809846809846809846809846809846809846809846809846809846809846809846809844809baa017002413c603a660a401a90010dd698430080445908401184300800984280800984200800984180800984100800984080800984000800cc004dd6980f183d9baa009800d2082808280e0ff9f80d2fddfd9dfe589cff8f6e6d9fae7c9b9969f9f8ddcace4bfafa9ecbe0ecc00520f6d3b3efb19f8dc2def587e499ccdfa3afee85bbe9f0f0fae2bda996e0d3bcb0cada82d305a414d8f91db494125734b9b83d5f55da191631b9fafa1ef51c7837f070f4b4101e94ff771360548036900020164034660326eb4c074c1e8dd500424101004097ae04bd701983e1980f9bae307d307e307e307e307e307e307e307e307e307e307e307e307e307a3754010660f860fa60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60fc60f46ea80212f5c097ae09bad301e307a3754011375a605060f46ea80226eb4c0d0c1e8dd50044cc13ccc04ccc1f0dd40031983e1ba80053307c3750008660f86ea000ccc1f0dd400125eb80dd6980f183d1baa008001402d98009983e1ba80033307c375000e660f86ea00192f5c13307c3301f375c60aa60f46ea8020cc1f0c0d4c1e8dd50041983e181b183d1baa0083307c3037307a375401097ae03307c3301f375c60a660f46ea8020cc1f0c0e0c1e8dd50041983e181c983d1baa0083307c303a307a375401097ae04bd704dd6980f183d1baa0089bad3028307a375401133019375a606860f46ea8021200499827998099983e1ba80053307c3750008660f86ea00092f5c06eb4c078c1e8dd5004000a016cc004cc1f0dd40039983e1ba80064bd704cc1f0cc07cdd7182c183d1baa0083307c303b307a3754010660f8607860f46ea80212f5c0660f86603e6eb8c1f4c1f8c1f8c1f8c1f8c1f8c1f8c1f8c1f8c1f8c1f8c1f8c1e8dd50041983e181e983d1baa0083307c303e307a375401097ae04bd704dd6980f183d1baa0089bad3028307a375401133019375a606860f46ea8021200699827998099983e1ba80053307c3750008660f86ea000ccc1f0dd400125eb80dd6980f183d1baa008001402d98009983e1ba80023307c375000e97ae09983e1980f9bae3068307a3754010660f8607e60f46ea8020cc1f0c100c1e8dd500425eb812f5c1375a603c60f46ea80226eb4c0a0c1e8dd50044cc064dd6981a183d1baa008480226609e66026660f86ea0018cc1f0dd40029983e1ba80043307c375000697ae0375a603c60f46ea802000500b66002660f86ea001ccc1f0dd40031983e1ba80053307c375000897ae09983e1980f9bae307d307a3754010660f8604060f46ea8020cc1f0c084c1e8dd50041983e1811183d1baa0083307c3023307a375401097ae03307c3301f375c60cc60f46ea8020cc1f0c090c1e8dd50041983e1812983d1baa0083307c3026307a3754010660f8604e60f46ea80212f5c097ae09bad301e307a3754011375a605060f46ea8022900152002402c9111119bc63378860986eb8c124c1fcdd500683e19bc4329800800cdd61841809840009baa33047329800800ccc20c04c2100400ccc20c04c2100401ccc20c04c21004018cc20c04c21004014cc20c04c210040112f5c14c0105d8799f80ff004004444b30010028800c6600200730870100299825000984300801200642100460ce66104026e9ccc20804c19ccc20804dd41824cc004cc20804c20c04c21004008cc20804c20c04c21004018cc20804c20c04c21004014cc20804c20c04c21004010cc20804c20c04c2100400d2f5c130524820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f83a44660aa0020048240cc20805301325830bbc622db0af03afbef1a7af93fe8556c58ac1b173f3a4ea105b974974f8c68c30faca94f8c63952694d79731a7d3f197004bd701984100983399841009ba83049330193308201375001a66104026ea0030cc20804dd400599841009ba800a4bd701bad3024308001375401c66104026106026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026108026100026ea80392f5c0661040260ce661040260486100026ea8038cc20804c128c20004dd500725eb812f5c097ae083da0022225980080144006330010039843008014c8cddb00119bb8375a610c026106026ea8004c140dd718379841809baa001308501002400c8418081ec601e66024660f66ea0008cc1ecdd4000a5eb80dd6980e983c9baa007191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919184780998550098558081b198550098558081a998550098558081a19855009855808199985500985580819198550098558081899855009855808181985500985580817998550098558081719855009855808169985500985580816198550098558081599855009855808151985500985580814998550098558081419855009855808139985500985580813198550098558081299855009855808121985500985580811998550098558081119855009855808109985500985580810198550098558080f998550098558080f198550098558080e998550098558080e198550098558080d998550098558080d198550098558080c998550098558080c198550098558080b998550098558080b198550098558080a998550098558080a198550098558080999855009855808091985500985580808998550098558080819855009855808079985500985580807198550098558080699855009855808061985500985580805998550098558080519855009855808049985500985580804198550098558080399855009855808031985500985580802998550098558080219855009855808019985500985580801198550098558080099855009855809821985580985600800a5eb80c10cc2a804c2ac04004c104c2a404c2a804004c104c2a004c2a404004c100c29c04c2a004004c100c29804c29c04004c0fcc29404c29804004c0f8c29004c29404004c0f4c28c04c29004004c0f0c28804c28c04004c0ecc28404c28804004c0e8c28004c28404004c0e4c27c04c28004004c0e0c27804c27c04004c0dcc27404c27804004c0d8c27004c27404004c0d4c26c04c27004004c0d0c26804c26c04004c0ccc26404c26804004c0c8c26004c26404004c0c4c25c04c26004004c0c0c25804c25c04004c0bcc25404c25804004c0b8c25004c25404004c0b4c24c04c25004004c0b0c24804c24c04004c0acc24404c24804004c0a8c24004c24404004c0a4c23c04c24004004c0a0c23804c23c04004c09cc23404c23804004c098c23004c23404004c094c22c04c23004004c090c22804c22c04004c08cc22404c22804004c088c22004c22404004c084c21c04c22004004c07cc21804c21c04004c074c21404c21804004c070c21004c21404004c06cc20c04c21004004c06cc20804c20c04004c064c20404c20804004c060c20004c20404004c05cc1fcc20004004c058c1f8c1fc004c054c1f4c1f8004c054c1f0c1f4004c050c1ecc1f0004c048c1e8c1ec004c044c1e4c1e8004c044c1e0c1e4004c03cc1dcc1e0004c038c1d8c1dc004c034ca600200300a99806a414d93c31fe3f145adef9f2fc9675b6b9d0b85abef4563cd096f8b9da5b717bbe389b3f9281060b4660ea016660ea98010140004bd702002222598008014400633001003983c8014cc03cdd6983c001000a00641d901441cc8398c1d4021072096600200314bd7044c8c8cc1c4c1c8c1cc004dd61839000994c0040066601e60e60053001003a5eb8244660e66ea00080050454cc1c5301018000330713750600a6eb4c1c80092f5c080088896600200510018cc00400e60ea005332233075374e660ea6ea0cc120004dd6983b0011bac3076003330753750660900026eb4c1d8c1dc0092f5c06eb0c1d0008dd6983a183a800a00641c930013071001998379838000a5eb8244b30010018b44cc1c4dd4198220011bad307200100141c0821906e11194c0040066601e00600530414820a02020383ffffffffef7f97fefe0693ef3aaa02efa21222c39e660ea77f3aa69a77b6f8390011112cc00400a200319800801cc1d400a646608a0046608e6eb4c1d4004dd6983a983b0009bac3074002400c83908cdc34c0040069041404040707ffffffffdeff2ffdfc0d27de755405df442445873ccc1d4efe754d34ef6df0752002a400080612082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e22225980099b88001480022660866601a006b300133710002900044cdc0a4000003100141b00051330433300d00400100241b044c9660026034660306eacc058c0a0dd500e00dc566002603530013756602c60506ea80726e50cdc5000805c520004888cc88cc004004008cc07000c078896600200300389919912cc004cdc8803801456600266e3c01c00a200300640b9133005005303400440b86eb8c0b4004dd698170009818000a05c456600260100031300700b8a50409914a0813229410261bae30133027375402914a0812a29410254528204a22259800980c1b8d0038acc004cdc3a4100026e34006330010039b92002800aed514a0813a294102745282048452820424528203c8a50407833225980099b8948000006264b30013371266e0120ca02001371a007130063302137533001003800d20384010660426ea6600200733700901c000d20104010660426ea66002007337009024000d20424010660426ea6600200733700904500800d20404010660426ea6600200733700906500800d20404010660426ea6600200733700904501000d2040401097ae08b203a3370090420099b8248328080062c80e0dd71805180e1baa009375a600860386ea8024888cc01c004cc02000c00913259800980c000c4c96600266e1d2001375a602a00315980099b8748004cc014dd59801980a9baa009008898021b8d375c602800314a0809a2c8098c05c0062c80a8cc010dd5980098099baa0070064044223232330010010042259800800c00e2646644b30013372200e00515980099b8f0070028800c01901544cc014014c06c0110151bae30140013756602a002602e00280a852f5bded8c0601c6ea8018dd7180818069baa003370e900145282016180600098039baa00c8a4d1365640141" + }, + { + "title": "bitcoin/peg_in.peg_in_validator.mint", + "compiledCode": "5925610101002229800aba2aba1aba0aab9faab9eaab9dab9a9bae0039bae00248888888896600330013005375401523009300a300a300a300a300a300a001918049805180518051805180518051805000c8c024c028c028c028c028c0280064601260146014601400325980099b8748100dc6800c40062c8022446e50cdc5001000cdc3a4001370e90024dc02400f23009300a300a001918049805000cdc024005229800800ccdc09b8d0020018012e3137009007cdc3a4005374a9000488c8cc00400400c896600200314bd7044cc8966002600a00513300d00233004004001899802002000a012300c001300d001402923009300a300a300a300a00191191919800800802112cc00400600713233225980099b910070028acc004cdc78038014400600c805a26600a00a60220088058dd718050009bab300b001300d001402c297adef6c60911919800800801911980180098010014dc3a400d374a90014dd2a4009371090004dc024002911111111111111111111111114c004c08c06a604403522225980099b890044800a266030b3001301700489980c001800c4cc06000400d02100144cc06000966002602c00913301800300189980c000801a0424085222233225980099b890064800a2b300133712008900144cc068c00800d2201200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f97610089980d18012441200000000000000000000000000000000000000000000000000000000000000000003001488120000000000000000000000000000000000000000000000000000000000000000000408d15980099b8948010012266034911200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100300200389980d1800a45200000000000000000000000000000000000000000000000000000000000000000003002488120000000000000000000000000000000000000000000000000000000000000000000408c811966002602e66e180112004891980c802000c48cc0640040110212cc004c05ccdc3001240091233019002001891980c8008012042912cc004c054cdc3000a400913370666e38008cdc1800a4008901044cdc319b8e0023370600290022404080fa4446466446600400400244b3001001801c4c8cc896600266e4401c00a2b30013371e00e0051001803204c8998028029816002204c375c604a0026eb4c098004c0a0005026198058020018a40012232330010010032259800800c530103d87a80008992cc004c0100062601e6604c00297ae08998018019814001204430260014091223259800980b000c4c8c8cc896600260540070068b204e375c604e0026eb4c09c008c09c004c088dd5001c566002601c0031323322598009814800c4c9660026034604a6ea800626464653001375c6058003375a6058007375c60580049112cc004c0c00120191640b4302c001302b0013026375400316409060500031640986eb4c098004c09c004c088dd5001c566002602a003132323298009bae30280019bad30280039bae302800248896600260580090088b20521814000981380098111baa0038b204040808100c080dd500148966002602a60406ea800a2646464646464653001375a6056003375c605600d375a605600b375c6056009375a6056007375c60560049111112cc004c0c801e26464b30013024001899192cc004c0d800a0251640cc6eb8c0d0004c0c0dd5001456600260380031323259800981b001404a2c8198dd7181a00098181baa0028acc004c08c00626464b300130360028094590331bae303400130303754005159800980b000c4c8c966002606c0050128b2066375c606800260606ea800a2b30013370e9004000c4c8c8cc896600260700070148b206a375c606a0026eb8c0d4008c0d4004c0c0dd500145902e205c40b8817102e18171baa001303100d8b205e18158009815000981480098140009813800981300098109baa0028b203e488888888a60026056013302b302c009911112cc004cdc4802a400d1330229800802c01200500140300071330220039800980f802c0120050014030815a4444b3001337120089003456600266e240092006899810cc004012007002800a0144892085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100899810cc004012007489200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402d3001301e002800d221200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402c81522b300133712900400144cc0852212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b1009800980f002400e603c0050014029133021980080140069101200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402d3001301e004801d221200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402c815102a4888c8cc00400400c896600266e2400c006291100899b8b3300a00500133002002301c00140ad2259800980f19b8600148012266e2d20fe033301800233706002900244cdc5a400066e2ccc01c008004cc060008cdc1980c800a400881412222223322323322598009813800c4c966002605060666ea80322646464b3001303b0028992cc004c0b0c0dcdd5000c4c8c8cc896600260800071598009818181d9baa0068991919194c004dd61821800cdd71821801cdd618218012444b3001304700489980e1823003899815000912cc00400a26605800a44b30010028cc004dc91bb3304a3047375403f59800981d98231baa33223302400223375e609a60946ea8004008dd6182518239baa027304a3047375403f14a314a0822a29426466002002660606eacc0c4c120dd501400a912cc004006297adef6c60899912cc004c0b8dd6982580144cc134008cc0100100062660080080028248c130004c13400504a24444b30010018a518acc004c13c006264b30013038375a60980031332259800982118269baa0018992cc004c108c138dd5000c4c9660026088609e6ea80062646464b300130570018cc004c15800a60ac0033303d3758608860a66ea80cc8cdd7982b982a1baa3057305437540026072660ac6ea40852f5c09112cc004c1680063300130590019823182b1baa02e91b923724003305930563754608c60ac6ea8c13cc158dd501b244446644b30013048305b375400715980080a4566002607e6eb4c114c170dd5182f982e1baa0058acc004cdc780800ac566002609130013756609860b86ea801a05301040e115980099baf304d305c375400c6080660bc60be60b86ea80152f5c1159800cc004c148dd7182f806400a0053758609a60b86ea801502b44c8c96600266e3cdd71830994c0040066eb0c158c17cdd50044cc184dd4802198309828182f9baa3062305f375401097ae04004444b30010028800c660020073065002cc004dd718320014dd71832000cdd698321832800a444660cc6ea4dc91b9259800982c19b8600148012266e2800800e266e2800c009062198331ba833706002900225eb8080190621800998261bae304e305e375400e90244566003300137049040024dc0240093704904040044dc124101010021370090044dd71827182f1baa3061305e375400f375c60aa60bc6ea8c184c178dd5003a44444446464664464b3001980099b8748120dc6803528528a0d08a508acc006600266e3cc03401803e942945068452844c8c96600266e24c8dd69838198040054c00402a60166eb4c1c0c1c40066eb4c1c000500719803804a401000314a115980099b8f489025120003301048010cc00c0240062b30013370e653001001980300540090011112cc004c18c006266e00cdc019b803370066e00cdc019b803371c018004602266e38030c178008c03ccdc70061808001180719b8e00c33700900300119b824820202020080cdc7006180680119b82482020202020100cdc700619b8048028008cdc1241010101010101000266e38030cdc02401800466e09208080808080808080023371c01866e01200e0028cc00400e6600e0180053051001400c8368dd6982a98361baa306f306c375402b13371e601e64b30013370e906a0099b8e001480022b30013370e902319b8e0014800a2b30013371e910103424652003301148018cc16c005200489982d800a40151641ad1641ad1641ac6600601290011bae3064306c375460de60d86ea8056294106a452820d441a866e00cdc019b803371c0029000180699b8e00148008c02ccdc7000a4008601466e380052006330580064810106820d022329800800cc01400e00480088896600260c40031323233014375a60e6002660bc00e66e00008dd69839983a0009980500300099b804804000a33001003998030028014c14000500320d823232337000026eb4c1b4c1b8cc01400c00660020053007375a60d860da003375a60d80028018cc00c00520082232323370066e00008dd6983718378009bad306e00133005003001337009008000911194c0040060070024004444b3001306000188014660020073232300c3370066e00008dd6983898390009bad3071001330080070013370090240014c13800500320d422325980099b88001483e80e2660d46ea0004cc1a930010101004bd70456600266e1d20fa030018998351ba83370066e3800cc15c008c028cdc70019804801198352610103004bd70456600266e1d20fc030018998351ba83370066e00cdc019b8e0033057002300a3371c0066012004601066e3800ccdc02400c004600e66e3800cc018008cc1a930010105004bd7045906620cc419866e3800800513370e6eb4c160c178dd51830982f1baa007375a60c260bc6ea8016294105c452820b8300148100dc62400114a082d2294105a452820b48a50416914a082d2294105a45905a18011bae304a305a375400660046eb8c128c168dd5182e982d1baa00345905722c82a0c158004c154004c140dd5000c5904e182918279baa0018b209a303f304e3754607c609c6ea8c144c138dd5000c5904c1bae304b001330273758607860986ea80b08c0e660026eacc0f4c134dd5181e98269baa001825522010040a50034128609c003002413082611323002304c003375c6094004824226603e609000426002609200482322c822060860026084002608200260786ea801a2c81d22c81e8dd6981e8009bae303d002303d001303837540031640d860740071640e06072002607200260686ea80322c8190dd7181b18199baa00a8acc004c0980062646644b3001302a3035375401d132332259800981e800c4c8c966002605e0031323322598009821000c4c8c96600260680031323322598009823800c4cc0a8dd61823000912cc00400a02313301f304800213001304900241191641106eb4c110004c114004c100dd5001456600260580031323298009bae30450019823000cdd698228012444b300130490028998161bac30480022259800801404e266042609400426002609600482422c8230608a00260806ea800a2c81f103e181f1baa00130410018b207e375c607e002608000260766ea800a2b300130270018991919191919191919194c004dd61824000cdd69824004cdd718240044dd69824003cdd698240034dd61824002cdd618240024dd69824001cdd718240012444444444b3001305200a899912cc004c110c13cdd500144c8c8c96600260ae00513301e3056003132598009824000c4c96600260b200313232598009825800c4c96600260b8003133023305b0010098b20b2305737540051598009821800c4c8c8ca60026eb4c1740066eb4c17400e6eb4c174009222598009830802403a2c82f060ba00260b800260ae6ea800a2c82a9055182a9baa00130580018b20ac305437540051598009820000c56600260a86ea800a00b1641551641488290c148dd5000c59054182a800982a80098281baa0028b209c3051013133035004225980080144cc0dc014896600200513303900d2259800801408226605c60ae0042600260b000482aa26605860aa0042600260ac004829a26605460a60042600260a8004828a2c82786090002608e002608c002608a0026088002608600260840026082002608000260766ea800a2c81c9039181c9baa001303c0018b2074375a60740026076002606c6ea803a2c81a04c8c8c8ca60026eb8cc00800520049bae330020014801a660446eb0c0ecc0e0dd500c119baf303c30393754607860726ea8c0a4c0e4dd50008032444b3001303f0018cc004c0f8006605660766ea804e4464653001001a4001003400444464b30010028a441200000000000000000000000000000000000000000000000000000000000000000008992cc00400626464b300130390018994c0040126eb4c1240066eb8c124c12800500518229baa0028acc004c0c40062646466446607cb3001303d001880144cdc54c0040320153370001400280e80090471bae303a3049375400666e2cdd6982518239baa001375c606e608e6ea8004dd698250011824982500098229baa0028991981d9980c9bae3049001007375c609260940026092608a6ea8009043208630433754002608c0071323259800981c800c4ca6002009375a6092003375c609260940028028c114dd50014566002606200313232980080540220039800804cc0d800600a804a6094609600480c0cdc00039bad304900130453754005132332233229800806c02e00398008064c0e40060108062606a660986ea0cc09c008004cc130dd49980e801181c800998261826982700225eb8101b1bae304b0023370001200260940026eb4c124004c114dd50012086410c60866ea8004c11800d04418230012086222329800804401a0039800803cc0d0006008803a00480b8cdc00028011b940029192cc004c0c0c0f0dd5000c4c9660026064607a6ea800626464b300130440028981b1bae3043304037540071641046eb8c108004c0f8dd5000c5903c1820181e9baa0018b2076302d303c37540032375c6600c00290044888c966002605730013756605e607e6ea8c0bcc0fcdd5000c00a9110342535300406d132598009819981f9baa0018992cc004c0d4c100dd5000c4c8c8c8ca60026eb4c1200066eb8c1200126eb8c12000e6eb8c1200092222598009826802c40262c82506090002608e002608c00260826ea80062c81f8c10cc100dd5000c5903e1818181f9baa302f303f37540031640f466010006004911111192cc004c0d8c104dd500344c8cc8966002606260886ea804a26644b3001303a3046375400313233021001159800994c0040064440039800982618249baa0029bac304c304937540533758607260926ea80a66eacc10cc124dd5014a444464b300130420018981c99828182898271baa00533050305130523052305230523052305230523052304e375405c97ae08acc004c0e800626066660a060a2609c6ea8014cc140dd380225eb822b300130410018981919828182898271baa00533050374c00497ae08acc004c0d0006266e952006330503051304e375400a660a0606e609c6ea80b92f5c11323374a90041982898290009982898291829800998289ba700533051374e008660a26e9800d2f5c0609c6ea801504c209841308260c130dd50021001114c00488966002607260986ea800e264b3001980080348880066064660a06ea4004cc140dd3001a5eb810064528c6600200d2220019819998281ba900133050374e00497ae040188260dd7182818269baa0038b209691111192cc004c110c13cdd5000c66002011222003982998281baa30533050375460a660a860a06ea8c14cc140dd5000c00a0068042294104e19815001919b894800a60026eacc100c140dd5182018281baa001803401502c48c9660026080003132323233001001375860a460a600644b30010018a508acc004cdc79bae30530010038a51899801001182a000a09c41446eb8c140004c130dd500145660026070003132323233001001375860a460a600644b30010018a508acc004cdd7982998281baa30533050375460a660a860a06ea8c14c00400e294626600400460a800282710511819198279828000a5eb80c130dd50014566002607e003132323233001001375660a460a600644b30010018a508acc004cdd780198279829800c528c4cc008008c15000504e20a230323304f30500014bd7018261baa0028acc004c0c800626530013041375a609a60a06606a6eacc140c144004dd71828000d28528a096304c37540051323232329800804488800a6eb8c14c0126eb8c14c00e6eb0c14c0066eb0c14c00a6eacc14cc15000500818298009829000982880098261baa0024128825104a2094304a3754002800a2b300159800981e18239baa0048992cc004c8c8cc8966002607200513259800981d18269baa303e304e375460a2609c6ea8016266e20008006266e2400800504c1bad3050304d3754007159800982080145284528a096412c60946ea8004cdc02410141ed4e266eb4c114c12cdd5002182698251baa304d304a3754002608460926ea80a633001303f375c609860926eaa60026eb0c0e4c124dd5014cdd69826000cc0280490094dd7182018249baa0029bac304c304d001402114a08238c120dd500244c8cc8966002606f30013756607660966ea8c0ecc12cdd5000c04a91010343504900409d198009806981d98259baa0019bae3042304b3754009375c609c0053758609c609e00480d22c8248c134004cc04cdd6181c98249baa029375a609800260906ea80110464566002606930013756607060906ea8c0e0c120dd5006c00e00a81222b30013370e9000cc004dd5981898241baa028801c01502444c0f260026eacc0c4c120dd501440429101046653415400409114a0823229410464528208c8a5041186094608e6ea80062c8228dd7182418229baa012303630453754606a608a6ea802a2c8218dd718230009823182380098211baa00689919191919191919194c004dd71827000cdd618271827800cc0f0c12cdd5181d98259baa0109827004cdd698270044dd71827003cdd698270034dd69827002cdd618270024dd61827001cdd69827001244444444444b3001304930553754013132330300011598009821982b1baa024899192cc004c174006264b30013046375a60b4003133225980098244c004dd59826182e1baa304c305c3754003023a441034350490040e1133225980098254c004dd59827182f1baa001812d221034350490040e915980099b874800660026eacc11cc178dd501f401e6eb8c17401503a456600330013054375c60c260bc6eaa60026eb0c138c178dd501f4026603e04e80f26eb8c154c178dd5004404e024816a2b3001980091191b923371466e28004004008dc900148ca6002003002a441004004444b30010028800c66002007306600299b8a001375c60ca00480190634dd7182b182f1baa008488a60020033300348810a54617053696768617368003002330634c102410000330634c102410000330634c105440000000000330634c1054400000000003306337526e48c008cc18cdd49b9237246004660c6980105440000000000330634c102410100330634c1225820000000000000000000000000000000000000000000000000000000000000000000330634c10544ffffffff00330634c102412200330634c1034200200033063375266006910116424950303332322d7369676e65642d6d65737361676500337149110c4246522d6d696e742d76313a003232329800800d220100a400080088896600266e1c004012200519800801cc8cdc519b8a0033371666e392211030313233343536373839616263646566003370600290102441003371666e3922011030313233343536373839616263646566003370c00290102441003371c00a0033055001400c8320dc68009b923371466e2922010b4246522d6d696e742d763100375c60b060c26ea802cdd980999831a60105440000000000330634c102410100330634c10948000000000000000000330634c102412200330634c10342512000330633752002660c6981054400000000004bd7019831a601054400000000004bd70198319ba937249101080000000000000000003306337526e48c008cc18d300102412200330634c1034251200033063375200297ae03306337526e4922010400000000003306337526e48c0092f5c3094800000000000000000081024101008102416a0019831a6102410000330634c1054400000000004bd70404576a456600266ebcc184c178dd5002008456600266e1e60026eacc138c178dd5002409a91104665341540040e86eb4c11cc178dd5004456600330010029bae3055305e375401100a407515980099b8f325980099b8f3302200100c0038cc00400602900c40bd1641746eb8c154c178dd50041810000c5660026466ebcdd318009bab304f305f3754609e60be6ea8010dd318009bab304f305f37540044646600200200444b30010018a5eb7bdb1822653001375c60c2003375660c4003306600248896600266e45221000038acc004cdc7a441000038800c401506344cc19ccdd81ba9003374c0046600c00c002831860c800283122b30013375e60c260bc6ea8c138c178dd50019830982f1baa001899b8798009bab3047305e375407d026a44104665341540040e86eb4c11cc178dd5004452820b88a50417114a082e2294105c452820b88a50417114a082e2294105c452820b88b20b8301e304c305c37540026604c6eb0c134c170dd501e00545905a198121bac304b305a3754074016660486eb0c174c168dd501d004c59058182e000c5905a198201bab304830583754609060b06ea8074004dd7182d182b9baa0248b20aa305930563754013164150304e001304d001304c001304b001304a0013049001304800130470013042375400c8200888cdc799803801000801a2c81e064b3001301b98009bab302830383754605060706ea800606948906424946434647004051132598009816181c1baa0018981c9baa303c303937540031640dc605260706ea8c0a0c0e0dd5000c59036198009bac30273037375402e6eb4c0e8c0dcdd5007912cc004cdc4a40000031330030020018b206c3001001222598009815800c4c0e800a33001003981d8014c064005003206a2232598009815800c4c8c966002607a0050048b2074375c6076002606e6ea800e2b30013023001899192cc004c0f400a0091640e86eb8c0ec004c0dcdd5001c59035206a30353754004606c60666ea802a2b3001301f0018991919912cc004c0acc0d8dd500144c9660026048606e6ea800626464660020026eacc0d0c0e8dd500d112cc00400629422b300132598009814181d9baa001899b8f375c607e60786ea8004012294103a181d181f000c528c4cc008008c0fc0050392078375c607660706ea80062c81b0c0e8c0dcdd5181d181b9baa3027303737546074606e6ea800a2c81a8cc040dd6181c181a9baa01523375e6072606c6ea8004008c0e0c0e4008c0dc004c0ccdd50054528206240c481888888cdc7cc00400e005001401400860606ea8020888cc88ca60020034800200880088896600200313302d3300b005002004899192cc004c0b8006264653001009803400730010079815800cc1000150074dd7181f9820001201c3370000a6eb4c0f8004c0e8dd50014566002604c003132329800804c01a0039800803cc0ac006608000a803a607e60800048068cdc00029bad303e001303a3754005132332298009bae304000299b8000700198208032445300100d805400b300100b9817801400500b4c0accc108dd41980e801801198211ba933013003302f00233042304330440054bd702022181f8009bad303e001303a375400481c1038181c1baa001303b00140e46e5000cdca001111111919814cc00401a00b00440213001330110060049800a40013001481026002904000cc00520c0014888896600266e24015200e8998174c004016011003801400500f00244cc0b80126002604c00b008801c00a00280790370a600200348102004b8c11111192cc006600266e1c004dd6981b981a1baa002a50a5140c9133029980080340160088040cc896600266e2400d200e8acc004cdc48012401d13302b9800801c016005001402c910120b22df1a126b5ba4e33c16fd6157507610e55ffce20dae7ac44cae168a463612a00899815cc00400e00b4892085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000403130013023002800d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000403081a22b300133712900800144cc0ad22120b22df1a126b5ba4e33c16fd6157507610e55ffce20dae7ac44cae168a463612a0098009811801c0166046005001402d13302b9800801400691012085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000403130013023003802d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000403081a10341bad303730343754004660526eb8c090c0d0dd50011bae3025303437540051640c86602000a006229344d95900301" + }, + { + "title": "bitcoin/peg_out.peg_out_validator.withdraw", + "compiledCode": "591508010100229800aba2aba1aba0aab9faab9eaab9dab9a9bae00248888888966003300130043754013230083009300930093009300930090019ba548002460106012003370e90004dc3a4005370e90022444444464653001300c37540032232330010010032259800800c530103d87a80008992cc004c010006260186602800297ae0899801801980b0012020301400140493010009980800124444b300130070048994c0044cc88ca600244b3001337129000000c4cc00c0080062c80aa4603260346034003222323322330020020012259800800c00e2646644b30013372200e00515980099b8f0070028800c01901c44cc014014c08801101c1bae301b001375a6038002603c00280e0cc01801000c520004888c8cc8966002602530013756602860366ea8c050c06cdd5000cdd719803001a401148903425353004011132598009809180d9baa0018992cc004c054c070dd5000c4c8c8c8ca60026eb4c0900066eb8c0900126eb8c09000e6eb8c0900092222598009814802c4cc896600260560031323259800980f98141baa00189991192cc004c090c0acdd5001c4c8c8c8ca60026eb4c0cc0066eb8c0cc00e6eb4c0cc00922259800981b80244c8c966002605a0031323259800981d80140322c81c0dd7181c800981a9baa0028acc004c0b000626464b3001303b0028064590381bae3039001303537540051598009815800c4c8c966002607600500c8b2070375c6072002606a6ea800a2b3001300b001899192cc004c0ec00a0191640e06eb8c0e4004c0d4dd5001456600266e1d20080018991919912cc004c0f400e01d1640e86eb8c0e8004dd7181d001181d000981a9baa0028b206640cc8199033206630333754002606c00f1640d0303300130320013031001302c37540071640a83300137246eccc0b8c0acdd5002660026eacc090c0acdd5181218159baa004809522104665341540040513015302b37540372302f3030303030303030001914c00400666e04dc6801000c009718912cc004c094cdc3000a400913370666e38008cdc1800a4008901044cdc319b8e00233706002900224040815a6e012002911b943371400400337009003cdc02401e91111111114c0048966002605e66e180052004899b8b483f80ccc020008cdc1800a4009133716900019b8b330070020013300800233706600c0029002206a91112cc004cdc48022400513300759800981880244cc01c00c00626600e00200681b800a26600e004b3001302f004899803801800c4cc01c00400d037206e911119912cc004cdc48032400515980099b890044800a2660126004006911200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f9761008998049801244120000000000000000000000000000000000000000000000000000000000000000000300148812000000000000000000000000000000000000000000000000000000000000000000040e515980099b8948010012266012911200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f97610030020038998049800a4520000000000000000000000000000000000000000000000000000000000000000000300248812000000000000000000000000000000000000000000000000000000000000000000040e481c966002606266e1801120048919804002000c48cc0200040110372cc004c0c4cdc30012400912330080020018919804000801206e9111919800800801912cc004cdc4801800c522100899b8b3300a00500133002002300900140e09111199119912cc004c0d4c0f0dd5008456600266e3ccc88ca6002003480026eb0c10cc100dd5009a00222259800800c4cc040cc03401400801226464b3001303c001899194c00402600d001cc00401e602a003304a005401d375c609260940048050cdc00029bad304800130443754005159800981d800c4c8ca6002013006800e600200f30150019825002a00e9824982500120163370000a6eb4c120004c110dd500144c8cc8a60026eb8c12800a66e0001c006609600c9114c004036015002cc00402e6032005001402d30443304c375066034006004660986ea4cc05400cc064008cc130c134c1380152f5c0807860920026eb4c120004c110dd50012084410860846ea8004c1140050431b94012372866e28dd7181b181e9baa0149800a50a4021337020226eb4c09cc0f4dd500a2f2403113370f30013756601e607a6ea80ba049489046653415400409866e0520000118a5040ed15980099194c00400644400398009821181f9baa0169bac3042303f375406137586070607e6ea80c26eacc0e8c0fcdd50182444464b3001303c0018981f19823182398221baa005330463047304830483048304830483048304830483044375406a97ae08acc004c0ec0062600e6608c608e60886ea8014cc118dd380225eb822b3001303a001899ba548010cc118c11cc110dd5002998231ba60024bd704566002603400313374a900319823182398221baa0053304630163044375406a97ae089919ba548020cc11cc120004cc11cc120c124004cc11cdd3802998239ba700433047374c00697ae03044375400a82110422084410860846ea801080088a6002444b3001303a3042375400713259800cc00401a4440033374a9002198231ba900133046374c00697ae0401914a3198008034888006600e6608c6ea4004cc118dd380125eb810062084375c608c60866ea800e2c820a4444464b3001303e3045375400319800804488800e6092608c6ea8c124c118dd51824982518231baa304930463754003002801a0108a5041106606e006466e25200298009bab303f30463754607e608c6ea800600d00540bd23259800981d000c4c8c8c8cc004004dd618241824801912cc00400629422b30013371e6eb8c12400400e2946266004004609400282210471bae304600130423754005159800981c800c4c8c8c8cc004004dd618241824801912cc00400629422b30013375e6092608c6ea8c124c118dd51824982518231baa30490010038a518998010011825000a088411c600c6608a608c00297ae030423754005159800981c000c4c8c8c8cc004004dd598241824801912cc00400629422b30013375e006608a609200314a3133002002304a00141108238c018cc114c1180052f5c060846ea800a2b300130180018994c004c0ecdd698219823198181bab30463047001375c608c0034a14a28208c108dd500144c8c8c8ca60020112220029bae30490049bae30490039bac30490019bac30490029bab3049304a001402060920026090002608e00260846ea8009040208041008200c100dd5000a002374a9001456600264646644b300130380028992cc004c0e4c104dd5181d98211baa30453042375400b1337100040031337120040028200dd6982218209baa0038acc004c0e400a2942294503f207e303e375400266e012080a0f6a713375a6084608660866086607e6ea8058c104c0f8dd51820981f1baa00130403041304130413041304130413041303d375405d15980099b8f32329800800d20009bac3042303f37540248008888c9660020051489200000000000000000000000000000000000000000000000000000000000000000008992cc00400626464b3001303d0018994c0040126eb4c1240066eb8c124c12800500518229baa0028acc004c0f00062646466446602eb30013041001880144cdc54c0040320153370001400280880090471bae30333049375400666e2cdd6982518239baa001375c6080608e6ea8004dd698250011824982500098229baa0028991980a198089bae3049001007375c609260940026092608a6ea8009043208630433754002608c0071323259800981e800c4ca6002009375a6092003375c609260940028028c114dd50014566002607800313232980080540220039800804cc05800600a804a609460960048060cdc00039bad304900130453754005132332233229800806c02e00398008064c06400601080626088660986ea0cc068008004cc130dd49980a801180c800998261826982700225eb8100f1bae304b0023370001200260940026eb4c124004c114dd50012086410c60866ea8004c11800d04418230012086222329800804401a0039800803cc050006008803a0048048cdc00028011b940120188981acc004dd59807981e9baa02e8125221046653415400409914a081da294103b4528207640ec4444464b3001980099b87001375a608860826ea800a94294503f44cc03e600200d005802201233225980099b890034803a2b300133712004900744cc04660020070058014005009244120b22df1a126b5ba4e33c16fd6157507610e55ffce20dae7ac44cae168a463612a00899808cc00400e00b4892085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a4412000000000000000000000000000000000000000000000000000000000000000000040293001300f002800d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a441200000000000000000000000000000000000000000000000000000000000000000004028820a2b300133712900800144cc04522120b22df1a126b5ba4e33c16fd6157507610e55ffce20dae7ac44cae168a463612a0098009807801c016601e00500140251330119800801400691012085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a4412000000000000000000000000000000000000000000000000000000000000000000040293001300f003802d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402882090411bad3044304137540046601e6eb8c0e8c104dd50011bae302b304137540051640fc6602000a00644444646601f3001006802c0110094c004cc044018012600290004c00520409800a41000330014830005222225980099b890054803a2660293001005804400e005001403400913301400498009809002c022007002800a01a411029800800d20408012e3044444b30013371200a900344cc032600200b0048014005008001c4cc03000e6002601600b0048014005008207822225980099b890044801a2b300133712004900344cc02e600200900380140050062452085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100899805cc004012007489200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000401d3001300a002800d221200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000401c81da2b300133712900400144cc02d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b10098009805002400e6014005001401913300b980080140069101200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000401d3001300a004801d221200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000401c81d903b0605860526ea8004dc3a400d16409c602460506ea8c084c0a0dd50009815000c59028192cc004cdc3a40806e3400620031640906eb8c078c094dd500499198008009bac30293026375402e44b30010018a5eb8226644b30013375e605860526ea8c0b0c0a4dd5181118149baa00201889981580119802002000c4cc01001000502718150009815800a0508b204c181200098118009811000980e9baa0018b2036301f301c3754003164068600a60366ea8c050c06cdd5000c590191bae3300400148010cc010dd61809180c9baa00a375a602460326ea8024c96600266e21200098009bab301230193754602460326ea800602d488106424946434647004009132598009808180c9baa0018980d1baa301d301a3754003164060600660326ea8c048c064dd5000c59017198019bac3011301837540126eb4c06cc060dd50040c00800888966002601a003130180028cc00400e6032005337009000800a006404c4464646600200200844b3001001801c4c8cc896600266e4401c00a2b30013371e00e00510018032030899802802980f0022030375c602e0026eacc060004c0680050180a5eb7bdb182446466002002006446600600260040052232598009806800c4c8c8cc8966002603a0070068b2034375c60340026eb4c068008c068004c054dd5001c5660026018003132332259800980e000c4c966002602260306ea800626464653001375c603e003375a603e007375c603e0049112cc004c08c012019164080301f001301e0013019375400316405c60360031640646eb4c064004c068004c054dd5001c5660026016003132323298009bae301b0019bad301b0039bae301b002488966002603e0090088b2038180d800980d000980a9baa0038b2026404c8098c04cdd50012444b3001300d3014375400b1323298009bad301a001980d800cdd6980d0012444b3001301e002899192cc004c050006264b300130210018998051bac302000122598008014036266016604400426002604600481022c80f0c070dd500145660026026003132598009810800c4cc028dd61810000912cc00400a01b13300b3022002130013023002408116407860386ea800a2c80d101a180d1baa001301d0028b2036180d000980a9baa0058b2026180a18089baa0058acc004c020012264646644b3001300d30143754005132598009806980a9baa00189919198008009bab30133018375401244b30010018a508acc004c966002602260326ea8006266e3cdd7180e980d1baa0010048a5040606030603800314a3133002002301d001405c80d0dd7180c980b1baa0018b20283018301537546030602a6ea8c038c054dd5180c180a9baa0028b2026330053758602c60266ea80108cdd7980b980a1baa0010023016301700230150013011375400b14a0807900f0c03cc040004c03c01d149a26cac80101" + }, + { + "title": "bitcoin/spo_bans.spo_bans.mint", + "compiledCode": "591646010100222222229800aba2aba1aba0aab9faab9eaab9dab9a9bae0089bac0079bad0069bad0059bad0049bae0039bad002488888888888889660033001300a375401f374a900048c038c03cc03cc03cc03cc03cc03cc03cc03cc03c0066e1d20009b80480066e1d2002918071807980798079807800c8c038c03cc03c0064601c601e003223232330010010042259800800c00e2646644b30013372200e00515980099b8f0070028800c01901044cc014014c0580110101bae300f001375660200026024002808052f5bded8c1370e90022444444444453001301900b980c005c88c8cc00400400c896600200314c103d87a80008992cc004c0100062601e6603800297ae0899801801980f0012030301c00140692225980080145300103d87a80008992cc004c03000a2601c660366e9ccc06cc060004cc06cc0640052f5c097ae08cc004012603a007300b002401080b8c06c009019489660026014602c6ea800a26464646464646464653001375a6046003375a6046013375a6046011375a604600f375c604600d375c604600b375a6046009375a6046006911111112cc004c0b002626464b3001301d001899192cc004c0c000a02d1640b46eb4c0b8004c0a8dd50014566002603600315980098151baa00280a45902b45902820503028375400260560151640a43023001302200130210013020001301f001301e001301d001301c0013017375400516405522329800800ccc01400c00a9000200222259800801440062653001004980f801cc8cdc01bad301c002003375c60340028020c07400901b4888c8cc88cc008008004896600200300389919912cc004cdc8803801456600266e3c01c00a20030064071133005005302200440706eb8c06c004dd6980e000980f000a0383300600400314800244b3001300a3016375400513232329800992cc004c06c0062b3001337129002180d000c5a26018603400280ca2c80e0dd5180e800cc0780066eb4c07400e6eb4c0740092222598009811001c4c8cc004004dd61811002112cc004006015132330030033025002375c6046002810a2c80f8603a0026038002602e6ea800a2c80aa44b3001300a30163754005159800980b9baa002800c59018459015488c96600260160031323259800980f00140122c80d8dd7180e000980c1baa0038acc004c0240062b3001301837540070028b20328b202c4058602c6ea80092222222222980098110054c088c08c02a4466014004466ebcc094c088dd50008014c01c01e44b300130123020375400513300400114a313300500114a280fa444646465300130280019814001cdd598140012444b3001301430273754007159800980c98139baa302b302c0048992cc004c070c0a0dd5000c4c8c8c96600260600051323322598009811000c4c8c966002606a0050048b20643033001302f37540071598009810000c4c8c966002606a0050048b20643033001302f37540071640b481684cc03c0084c8c96600260660031323259800acc004cdc79bae3034002011898111bad303430350018a5040bd19800805cdd6981a181a981a9bac30340049bae3034001802c01901045902f181a0009bac30320018b2060303200132330010010072259800800c52f5c113233223322330020020012259800800c400e2646606e6e9ccc0dcdd48029981b981a0009981b981a800a5eb80cc00c00cc0e4008c0dc0050351bab3032003375c605e00266006006606800460640028180c0b0dd50009817801c5902d1817000981700098149baa0018b204e302b30283754007164099164098302800130270013022375400691111119912cc004c06800a2646644b3001301d0018992cc004c0bc006264b3001301f302b375400313232332259800981a001c0222c8188dd698188009bae30310023031001302c37540031640a8605c0031640b060546ea802e2b3001301b0018991919912cc004c0c800e00d1640bc6eb8c0bc004dd69817801181780098151baa00b8b205040a0264b3001301c3028375401513259800980e98149baa330093758605a60546ea80500062b3001301b330103756603460546ea805000e2b3001301b98009bab301a302a3754029003a450862616e2d726f6f7400403d15980099199119acc00528c48a6002009002911112cc004c09cc0ccdd5001456600266e3c00c01a2b300130259800804401e00680ca2b3001330114c0103d87a800030373034375400513375e98103d87a80000018a5040c914a08192294103245903220168b20560064890862616e2d726f6f74009800800c01200948810862616e2d726f6f7400400c6eacc06cc0acdd500a9bac3019302a375402913375e002603e660586ea4088cc0b0dd4010a5eb822941028452820508a5040a11640a0605860526ea802a2646464b3001301d330123756603860586ea80580162b3001301d98009bab301c302c375402d00580120228cc0040166eacc080c0b0dd500b4dd69817801a00c8a5040a914a08150c966002603060566ea8006264b30013020302c3754003132323259800981a00144c8cc8966002604c00513259800981c000c4cc05cc0dc00400a2c81a8c0ccdd5001c566002604800513259800981c000c4cc060c0dc00400a2c81a8c0ccdd5001c59031206230303754002266026004264b300130233031375400313035303237540031640c0606860626ea8014c0cc00e2c8188c0c8004c0c8004c0b4dd5000c5902b181798161baa0018b2054301a302b375530013758603460566ea8056009004800a0063371491010462616e2f00375c605a605c00260526ea80290271111192cc004c080c0b0dd5000c4c0c0c0b4dd5000c5902b1980a80212cc004cdd7981818169baa3030302d375400266e9520023302f375200897ae08980f4c004dd5980d98169baa001801c00901245282056302737540126eb8c0a8c09cdd5003c4cc89660026034009132332259800980f98159baa00d899192cc004c0c800a264b30013022302e37540031323259800981118181baa0018992cc004c8c966002604a6eb4c0d000a2b30013371e9110862616e2d726f6f74000018a51899b8f4890462616e2f003300c480200050324590321bae30320013300b3756604060646ea8c080c0c8dd5001800c660020033756604c60646ea80726eb4c0d4c0c8dd5009a0188a5040c06eb8c0d0c0c4dd5000c5902f181998181baa303330303754603c60606ea8004c0c8c0bcdd5000c5902d198069bac3031302e37540300091640bc6eb4c0c0004c0b0dd5006c5902a18168009816981700098149baa0098acc004c054012264660220162b3001301b30293754003198009bae302d302a37540032302e302f302f302f0019bae301a302a37540172302e302f302f302f302f302f302f302f0019bad302d302e302e302e302e302e302e302e302e302a3754017222598009810000c4c0c000a3300100398188014c07c00500320569b88480026e0120029111192cc004c0cc006264b30013370e90009bad30300018acc004cdc79bae302f0010058991919800800802912cc00400629462b300132325980099b8f002009899b8748004006260500028198cc068010004dd7181b000c4cc008008c0dc006294103120683756604060606ea801a294102e45902e1819000c590301980d9bab301e302e37540080052223259800980f98169baa00189919912cc004c088dd69818801c4c966002603c60626ea8006264b3001302630323754003132323259800981d00144c8cc8966002605800513259800981f000c4c966002605c60746ea80062b3001303b37540030038b20788b2072303d0018b207630393754007159800981500144c966002607c003132598009817181d1baa0018991919912cc004c10c00e00f1641006eb8c100004dd718200011820000981d9baa0018b2072303d0018b2076303937540071640dc81b8c0d8dd500089980c8010acc004c0a0c0d8dd5181d181b9baa0058acc004cdc780380644cdc7804005c528206a8b206a30390038b206e30380013038001303337540031640c4606a60646ea80062c8180c080c0c4dd5180f98189baa0078b205e375c605c0026eb8c0c8c0bcdd5001198039bab301c302e37546038605c6ea801000e2c8160c0c0c0b4dd5181818169baa301b302d375400723370e90201b8d001919b87480e0dc6800c88c8cc00400400c896600200314a115980099b8f375c606200200714a3133002002303200140b0817a444453001004801c00a002802a44b3001337120029000452002899b8248010cc008008c07800502a48a6002003337026e34008006004b8c244444444444444453001375c601e60746ea806e6016017323232598009817181e1baa0018992cc004c0bcc0f4dd5000c4cc88cc896600266e240080062b30013371266e040040080ee2003164101164100b30013031303f3754605c60806ea8c10cc100dd50034400a2601e00481f1660026062607e6ea8c0b8c100dd5181718201baa0068800c4c0c800503e1bad3041303e37540046eb4c104c0f8dd5000c5903c1820182080145903b181f8009981e981f181d9baa303e303b37540026607a607c60766ea8c0a4c0ecdd5000a5eb80c034c0e8dd50124c034c0e8dd500dc89660020031480022601666004004608000281ea44b30010018a51899912cc0066002660100020054a14a281e226600800800314a081e0dd7181f8009820000a07a9801001244444453001225980099b8948000006266010004003164105372866e2801c056600600730020029119b820023003303500148888a60026600a6eb0c0d0c118dd50181bad30343046375404f375c6600a64b3001301798009bab303530473754606a608e6ea8006089489064249464346470040b113259800981a18239baa001898241baa304b30483754003164118606c608e6ea8c0d4c11cdd5000c59045198029bac3034304637540606eb4c0d4c118dd5013a40253232598009826000c566002607264653001001823520004004444b30010028800c66002007305000299b8000133032004375c609e004801904d1bab303630483754606c60906ea800a26eb8c12c0062c82322c8248c8cc004004110896600200314bd7044cc8966002607930013756607260966ea8c0e4c12cdd5002c00a012818226609a6ea4008cc0100100062660080080028248dd718260009826800a0943300537586092608c6ea80c0dd6982498231baa02791112cc004cdc3a400c600e009159800980300245660026034007159800980d00144cdc4a400000314a082422941048452820908a50412091112cc004c0f4c124dd5006c4c9660033001047823411608880122b300130160118acc004c05c07e2b30019800802c01202280c22b3001980081ac0260070474065159800981f198189bab303b304b375406a0431323232980091114c004c154c148dd5198089bac305530523754078011375860aa60a46ea80f26eb0c104c148dd501e4dd5982118291baa03c91111981d00109981d0008acc004c1240122b30013375e0066096660b06ea40712f5c115980099b8948008dd6982c982b1baa0028acc004cdc41bad3059305637540040a115980099b8730133758605660ac6ea8008dd6982c982b1baa0028acc0066002608e60aa6ea8c114c158dd5001528528a0a88acc0066002660406eb0c0acc158dd5001015528528a0a8899baf001323232304e3305b305c0023305b305c0013305b980099b89053375a60b860b26ea800e980103d87a8000a60103d8798000415c60ba60ba00260b800260ae6ea8004c8c130cc164dd40009982c9ba83370064b3001337100380031001880e20ac375a608a60ae6ea800ccc048148004cc1666002942980103d87a8000a60103d87980004154660b26e9ccc164dd48159bac302c3057375400697ae03025375a60b260ac6ea800a2941054452820a88a50415114a082a22941054452820a88a504150911112cc005660026608800401314a314a082c2264b3001304b3057375400313322598009826982c9baa0018acc004cdd7804182e982d1baa0028994c004c124c16cdd5001c03644445300100680948888966002b30013375e01400b15980099b8f008003899baf0060018a50418d14a0831a264b3001305930653754011159800982c98329baa0038acc004cdc780480bc660020034c0103d87a8000983498331baa008983498331baa003404114a083222c83222b300130573065375400715980099b8f3303e0150090168cc00400660b6660d06ea4cc0b40240552f5c13069306637540113069306637540068082294106445906420c83370200801316418c81e1037182e982d1baa0018b20b08b20b0305b30583754002660160080551641586601400801b16415481252210862616e2d726f6f7400a4410462616e2f00a401080b8896600266e2000520008a6103d87a8000899801801000a09a30010012225980080145300103d87a80008acc004c10400626086660a060a200497ae08cc00400e60a40053040001400c826104f452820928a50412514a0824a2941049452820928a5041246eb4c134c128dd5006c5660033001046822c112086800a2b300130150108acc004c05807a2b30019800802400e02080ba2b3001980081a40220050464061159800981dcc004dd5981d18251baa0348104cdc524410462616e2f0001040bd132980091114c004cc038dd6182918279baa039375a60a460a660a660a660a660a6609e6ea80c26601c6eb0c0f8c13cdd501c9bad3052305330533053305330533053304f37540613300e3758607c609e6ea80e40866eacc0fcc13cdd501cc8888888cc0e80085660026606600c00b1598009824803c56600266e3c00c072266ebc008c12ccc161300101010033058375066e00068cc044145200233058980099b890504800a98103d87a8000a60103d87980004150660b06e9ccc160dd481525eb812f5c114a082a22941054452820a848888a600260ae60b060a86ea8016013222229800804c03a44445300100d809c8888966002b30013375e01e01515980099baf30663063375401e60cc60c66ea80162b30013371e01a01113375e01800f14a0830a2941061452820c2899912cc004c158c190dd500244c966002b30013057980080a406e00c825a2b30013375e01260b6660d06ea40092f5c115980099baf00400e899b8f3303e0180060198a50419114a08322294106444c96600260b460cc6ea80422b30013371e022037159800acc004c160c198dd5007c528c4c004cc07400cdd7183518339baa00f419519800802530103d87a8000983518339baa010804400e005005405114a0832a2941065456600266e3ccc0fc06404406a2b300159800982c18331baa00f898009980e808803c56600260026603a02200f130013301d003375c60d460ce6ea803e294106520ca8cc00401260b8660d26ea4cc0b80440652f5c1306a30673754021008801c00a00a80a22941065452820ca41946ebd30103d87980008b20c830683065375400916418c66e04024038cc0a800c0562c830903a206a40c0810d22010862616e2d726f6f7400a4410462616e2f00a401080a0896600266e400080062980103d87980008acc004cdc7801000c530103d87a80008a6103d87b8000412882522941048452820908a50412114a08242294104845282090412011640a0605860526ea80262941027204e2232598009817000c4c0b40062c8158cc058008004dc6240008128c090dd500291119807992cc004c070c0a0dd5000c4c96600266ebccdd2a40086605866e9520023302c375200a97ae04bd701814800c4c0a80062c8140c8cdd81816800981698170009bac302c3029375400316409cb300133710002900045300103d87a8000899803001000a04c14a2229344d9590081" + }, + { + "title": "bitcoin/spos_registry.spo_registry.mint", + "compiledCode": "591e5a010100222229800aba2aba1aba0aab9faab9eaab9dab9a9bae0059bad0049bae0039bae002488888888889660033001300737540192300b300c300c300c300c0019ba5480024464646600200200844b3001001801c4c8cc896600266e4401c00a2b30013371e00e0051001803201a8998028029809802201a375c60180026eacc034004c03c00500d0a5eb7bdb182460166018003370e90014dc3a400091111114c004c04801e602200f2232330010010032259800800c530103d87a80008992cc004c010006260146602a00297ae0899801801980b80120223015001404d22329800800ccc01c00c00a9000200222259800801440062653001004980c001cc8cdc01bad3015002003375c60260028020c0580090142444465300130123754003223300500223375e6032602c6ea800400a602c00a9112cc004c02400e33001375c6032602c6ea80126e1d2004911919800800801911980180098010014c054dd5000a44446644b3001300f0038acc004c070dd5003c0062c80ea2b30013010003899191919191919194c004dd69813800cc0a00066eb8c09c0226eb8c09c01e6eb8c09c01a6eb4c09c0166eb4c09c0126eb4c09c00e6eb4c09c00922222222259800981880444cc054dd61818004112cc00400a029133015303200213001303300240c11640b83027001302600130250013024001302300130220013021001301c375400f1598009802801c4c8c8c8c8c8c8c8ca60026eb4c09c0066050003375c604e011375c604e00f375a604e00d375a604e00b375a604e009375a604e007375a604e0049111111112cc004c0c402226602a6eb0c0c0020896600200501489980a981900109800981980120608b205c1813800981300098128009812000981180098110009810800980e1baa0078acc004cdc3a400c0071323232323298009bad30240019812800cdd69812002cdd698120024dd69812001cdd698120012444444b3001302b0058998079bac302a0052259800801403a26601e605800426002605a00481522c8140604800260460026044002604200260386ea801e2c80d101a203440684464b300130100018991919912cc004c09400e00d1640886eb8c088004dd698110011811000980e9baa0038acc004c0440062646644b300130240018992cc004c050c080dd5000c4c8c8ca60026eb8c09c0066eb4c09c00e6eb8c09c00922259800981580240322c8140604e002604c00260426ea80062c80f8c08c0062c8108dd698108009811000980e9baa0038acc004c01800626464653001375c6046003375a6046007375c60460049112cc004c09c01201116409030230013022001301d375400716406c80d901b180d9baa0021980091192cc004c084006260400031640786602400400322598009807980d9baa0028991919912cc004c09000e00b1640846eb8c084004dd718108011810800980e1baa0028b2034912cc004c03cc06cdd5001456600260386ea800a0031640751640692232598009808000c4c8c96600260460050048b2040375c6042002603a6ea800e2b300130110018acc004c074dd5001c00a2c80f22c80d901b180d9baa0029180f180f980f800c8888a60020090038014005005496600266e1d2040371a00310018b20329b804800a6e212000912cc004cdc8001000c530103d87980008acc004cdc7801000c530103d87a80008a6103d87b8000406880d24446466446600400400244b3001001801c4c8cc896600266e4401c00a2b30013371e00e0051001803204289980280298138022042375c60400026eb4c084004c08c0050211980a0020018a4001229800800ccdc09b8d0020018012e31371890004889660026020003130200028cc00400e6042005337009000800a006406d22372866e280080066e012007912cc004c03ccdc3000a400913370666e38008cdc1800a4008901044cdc319b8e0023370600290022404080d26e01200f980c9baa0054888888888888888888a6002464b30013018302e375400313259800981198179baa00189919192cc004c0dc00a2646644b300130290028992cc004c0ec00626603660740020051640e0606c6ea800e2b3001302a0028992cc004c0ec00626603860740020051640e0606c6ea800e2c81a103418199baa001133017002132598009814981a1baa0018981c181a9baa0018b206630373034375400a606c0071640d0606a002606a00260606ea80062c8170c0c8c0bcdd5000c5902d180818171baa001911919800800801912cc0040062900044cc8966002600a005130120018800a062303400133002002303500140c92223232329800981b000cc0d800e6eacc0d800922259800980f981a9baa0038acc004c0a8c0d4dd5181c981d00244c9660026054606c6ea80062646464b3001303e00289919912cc004c0c000626464b300130430028024590401820800981e9baa0038acc004c0c400626464b300130430028024590401820800981e9baa0038b207640ec26603c00426464b30013041001899192cc0056600266e3cdd71821001008c4c0ccdd698211821800c528207a8cc00402e6eb4c108c10cc10cdd618210024dd71821000c01600c80822c81e8c108004dd61820000c5903e18200009919800800803912cc004006297ae08991991199119801001000912cc004006200713233045374e6608a6ea4014cc114c108004cc114c10c0052f5c066006006608e004608a0028218dd598200019bae303d001330030033042002304000140f860746ea8004c0f400e2c81d8c0f0004c0f0004c0dcdd5000c59035181c981b1baa0038b20688b2068181b000981a80098181baa003980300348c9660026030605c6ea8006264b30013023302f375400313232332259800981c001c40162c81a8dd7181a8009bae30350023035001303037540031640b86064605e6ea80062c8168c040c0b8dd5000c8888c966002604a60626ea80062606a60646ea80062c8180cc08401096600266ebcc0d4c0c8dd5181a98191baa0013374a90011981a1ba90044bd7044c09a60026eacc09cc0c8dd5000c00e00480722941030488896600266e240112002899804acc004c09001226601200600313300900100340bc00513300900259800980d00244cc02400c006266012002006817902f48888cc896600266e2401920028acc004cdc48022400513300b30020034881200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f9761008998059801244120000000000000000000000000000000000000000000000000000000000000000000300148812000000000000000000000000000000000000000000000000000000000000000000040c515980099b8948010012266016911200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f97610030020038998059800a4520000000000000000000000000000000000000000000000000000000000000000000300248812000000000000000000000000000000000000000000000000000000000000000000040c4818966002604866e1801120048919805002000c48cc02800401102f2cc004c090cdc300124009123300a0020018919805000801205e9111919800800801912cc004cdc4801800c522100899b8b3300800500133002002301100140c12259800981119b8600148012266e2d20fe033300a00233706002900244cdc5a400066e2ccc014008004cc028008cdc19807000a4008816a446047300137566048605e6ea800a0034890642465254525900402d2259800981198171baa0028998098008a5189980a0008a5140b49111111111114c00488cc0f4dd4198069bac303e303b375400446034660566eacc0c4c0f0dd51818981e1baa0010023303d37506601a6eb0c074c0ecdd50011180d198159bab3031303c375400200497ae0911114c00401200b222229800804402a44445300100c807c8888966002b30013375e01e01515980099baf3050304d375401e60a0609a6ea80162b30013371e01a01113375e01800f14a0825a294104b452820968cc00403601900b99b8100900e8034012007002800a0208b2096406480a100f4896600266e252000001899805801000c590394888896600266e24015200689980b4c004016009002800a01600389980b001cc004c054016009002800a01640f122225980099b890044801a2b300133712004900344cc056600200900380140050092452085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b10089980acc004012007489200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402930013014002800d221200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402881da2b300133712900400144cc0552212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b1009800980a002400e60280050014025133015980080140069101200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402930013014004801d221200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402881d903b24444466446644b300130350168acc004c0d4c104dd5198171bac3045304237540666072660886ea40fccc110dd401f25eb822b30013036330313756607460846ea80cc0b22b3001303698009bab303a3042375406702ca45087265672d726f6f7400407915980099baf4c1049f0001ff00374e6601206605913233223359800a518914c0040120052222259800981f98259baa0028acc004cdc7801803456600260813001008803c00d028456600266028980103d87a8000304f304c375400513375e98103d87a80000018a50412914a08252294104a45904a20308b208602f489087265672d726f6f74009800800c0b605b4881087265672d726f6f740040446eacc0ecc10cdd501a1bac30243042375406714a082022941040452820808b20808cc00488c8cdc51bae30483045375400330014a1480226eb4c0e8c114dd5000af24608e60886ea8cc024dd6182398221baa0020019111119912cc0056600266024607c60926ea800800e2b300133012001003899baf304c30493754002609860926ea8c0f8c124dd50014528208e8a50411d13375e60300026080660966ea4010c134c124dd5180c181f18249baa0028a50411c660186eb0c128c11cdd5002802198061bac30293047375400a0072232329800800d2000801a0022223259800801452201200000000000000000000000000000000000000000000000000000000000000000008992cc00400626464b3001303f0018994c0040126eb4c1400066eb8c140c14400500518261baa0028acc004c10000626464664466050b30013043001880144cdc54c0040320153370001400280d800904e1bae30323050375400666e2cdd6982898271baa001375c6086609c6ea8004dd698288011828182880098261baa002899198129980b9bae3050001007375c60a060a200260a060986ea800904a2094304a3754002609a0071323259800981f800c4ca6002009375a60a0003375c60a060a20028028c130dd50014566002608000313232980080540220039800804cc0b400600a804a60a260a40048078cdc00039bad3050001304c3754005132332233229800806c02e00398008064c0c000601080626090660a66ea0cc09c008004cc14cdd49980d801181800099829982a182a80225eb810121bae30520023370001200260a20026eb4c140004c130dd50012094412860946ea8004c13400d04b18268012094222329800804401a0039800803cc0ac006008803a0048070cdc00028011b940024889660026072033159800981c98221baa030899911919191919194c004c1440066eb4c1400066eb8c13001e6eb8c1400226eb8c14001a6eb8c1400152222225980098239bad305300d899194c004dd7182c000cdd7182c182c800ccc04c118dd6982c0062444b30019800cc004cc074dd6182d982c1baa049375a60b601d3301d3758607460b06ea8124dd6982d806c0166eacc140c160dd5024c8888888cc1100084c9660026605000e00d1598009829804456600266e3c0100462b30013375e00660ae660c46ea402ccc188dd480525eb822b30013371e6f200400122b30019800808400601eb95466002017372400300e5daa294105e452820bc8a50417914a082f2294105e452820bc3371466e28cdc519b8a48810b626966726f73742d73706f00003375c60c460be6ea8008dd7182a182f9baa002008405d042a441087265672d726f6f7400a44100a400081ca2b30013375e9801049f0102ff00374e6603e09208519800824c02a6eb4c16c02e6644b30013371e6602c00a00200519800802c02e00280d22c82c0c0e0dd7182d982c1baa3027304d305837546603a6eb0c16cc160dd50248051bac305b305c00b829a02a8a50415914a082b060a86ea8c09c00660026eb0c0d4c14cdd502240f607b00440851641443050001304f001304e001304d001304c001304b00230453754060660566eacc0f4c114dd501b017c590434566002605c033159800981718221baa030899911919191919194c004c1440066eb4c1400066eb8c13001e6eb8c1400226eb8c140019222225980099b8748004dd6982900644c8cc89660033001222298009980f1bac305c305937540946eb4c17003e6603c6eb0c0ecc164dd50251bad305c00e9bab30513059375409522222223304500215980099814003002c56600260a600f15980099b8f0030118acc004cdc79bae30633060375400401b15980099b8f3790020007198008084cdc519b8a48810e626966726f73742d7265766f6b650000300c807ae5514a082f2294105e452820bc8a50417914a082f1222298008044c180c184c174dd5002400e60c060c260ba6ea802e44444444464b3001305b3066375400713259800acc004cdc3a4003300100d809c015044456600266ebc024c17ccc1a8dd480125eb822b30013375e00e00713371e6608402000a02314a083322941066452820cc8acc004c16cc19cdd5005456600266e3c02c04a33001008a6103d87a8000983598341baa00a803400a003003403114a083322b30013371e66084020016023198008044c17ccc1a8dd49982180580825eb8260d660d06ea802a00d002800c00d00c452820cc419916419860d460ce6ea800e2c8328cc10400c039023207f489087265672d726f6f7400a44100a400081b22b30013375e9801049f0201ff00374e6603808c07f19800823401e6eb4c1600226644b30013371f3001004804400501700144cc04c0100062c82a8c0d4dd7182c182a9baa3024304a30553754660346eb0c160c154dd50230039bac3058305900882820248a50414d14a08298dd7182b18299baa3026304830533754002660220886eb4c15802ccc05cdd6182a98291baa043375a60aa0131641403050001304f001304e001304d001304c001304b00230453754060660566eacc0f4c114dd501b017c59043456600266e1d2006304437540611332232323233225980098201bad304c0068992cc006600266e3d220100001a50a51412d1323259800982198271baa0018992cc004c110dd69828000c4cc8966002b30013371e6eb8c154c148dd500200344cdc79bae30510030078a50414115980099baf4c01049f0102ff00374e660320860791598009980d982398291baa00104d8acc004c8cc004004dd6182b18299baa0442259800800c528c56600330013301d30493054375460ae00209f4a14a2829226600400460b000314a08291055456600266e3e60026eb8c154c148dd5001401e6eb0c154c15802101218191bae3055305237546042608e60a46ea80063300198009980b9bac3055305237540866eb4c1540266602e6eb0c0d0c148dd50219bad3055008cc004dd6181a18291baa04381e40f200e81026eacc128c148dd5021c8888888cc0f80085660026604200c00b1598009826003c56600266e3c00c03a266ebc0080262941057452820ae8a50415c808a0794881087265672d726f6f7400a44100a4000819a2941050452820a08a50414114a0828229410501811982298281baa003330153758608a60a06ea8104dd6982980445904e1981a9bab3044304f37546088609e6ea800800e2c8268c144c138dd5182898271baa3043304e3754002660246eb0c108c134dd501f1bad30500088b2096375c6602264b3001302b98009bab3042304d37546084609a6ea800608f489064249464346470040a513259800981b98269baa001898271baa3051304e3754003164130605e609a6ea8c108c134dd5000c5904b198089bac3041304c375407a6eb4c13c015201a8b2094304e001375c6092008609a00260980026096004608a6ea80c0cc0acdd5981e98229baa03602f8b2086410c82188200888cc88ca60020034800200880088896600200313302033012005002004899192cc004c0f4006264653001009803400730010079815800cc1400150074dd718279828001201c3370000a6eb4c138004c128dd50014566002607c003132329800804c01a0039800803cc0ac00660a000a803a609e60a00048068cdc00029bad304e001304a3754005132332298009bae305000299b8000700198288032445300100d805400b300100b9817801400500b4c11ccc148dd419813001801198291ba93301a003302f00233052305330540054bd70202218278009bad304e001304a3754004824104818241baa001304b00141246e5000cdca0011111111114c0040126098609a60926ea8026011007911111111192cc004c11cc148dd5001c4c966002b300130489800808c03e00a81822b30013375e00e6096660ac6ea40092f5c115980099baf003009899b8f3302e00c00500d8a50414914a08292294105244c966002609060a86ea802e2b30013371e01801f159800acc004c124c150dd50054528c4c004cc0c800cdd7182c182a9baa00a414d19800804d30103d87a8000982c182a9baa00b803c00e005004404514a0829a2941053456600266e3ccc0bc03403003a2b3001598009824982a1baa00a8980099819006003456600260026606401800d1300133032003375c60b060aa6ea802a294105320a68cc0040266098660ae6ea4cc0c00300352f5c1305830553754017007801c00a008808a2941053452820a6414c6ebd30103d87980008b20a43056305337540071641446605a006014807888888c8cc072600200d005802201e98009980d0030024c00520009800a4081300148200066002906000a44444b30013371200a900744cc086600200b008801c00a00280680122660420093001301e005804400e0050014034823853001001a40810025c6088888c96600330013370e0026eb4c11cc110dd5001528528a08489980e4c00401a00b004403c6644b3001337120069007456600266e24009200e89980f4c00400e00b002800a012488120b22df1a126b5ba4e33c16fd6157507610e55ffce20dae7ac44cae168a463612a0089980f4c00400e00b4892085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a4412000000000000000000000000000000000000000000000000000000000000000000040293001301b002800d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402882222b300133712900800144cc07922120b22df1a126b5ba4e33c16fd6157507610e55ffce20dae7ac44cae168a463612a009800980d801c0166036005001402513301e9800801400691012085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a4412000000000000000000000000000000000000000000000000000000000000000000040293001301b003802d2212085c09af929492a871e4fae32d9d5c36e352471cd659bcdb61de08f1722acc3b100a441200eb923b0cbd24df54401d998531feead35a47a99f4deed205de4af81120f976100a44120000000000000000000000000000000000000000000000000000000000000000000402882210441bad304730443754004660386eb8c0e4c110dd50011bae3026304437540051641086603200a00611598009805001c4c8cc8966002601860306ea80122b300130193754009132598009806980c9baa0018992cc004c03cc068dd5000c66002601c660146eacc04cc06cdd50061bae301e301b37540034a14a280ca2c80c8c074c068dd5180e980d1baa300f301a3754603a60346ea80062c80c0cc014dd6180e180c9baa00a0028b20348b202e301a001301a301b0013016375400914a080a10140c054c0580108a4d1365640141" + }, + { + "title": "bitcoin/treasury.treasury_info.mint", + "compiledCode": "59086401010022229800aba2aba1aba0aab9faab9eaab9dab9a9bae0049bad0039bae0024888888888966003300130063754017370e9000488c8cc00400400c896600200314bd7044cc8966002600a00513300e00233004004001899802002000a014300d001300e001402d374a900048c028c02cc02cc02cc02c0064464646600200200844b3001001801c4c8cc896600266e4401c00a2b30013371e00e0051001803201889980280298090022018375c60160026eacc030004c03800500c0a5eb7bdb1824601460160032300a300b300b0019b874800a6e1d20019b87481026e1d20049ba54800922222222222229800980b806cc05803644b3001300e3014375400513232332259800980e801c0162c80d0dd7180d0009bae301a002301a0013015375400516404d2232330010010032259800800c5300103d87a80008992cc004cdd7980d980c1baa001004898079980d000a5eb82266006006603800480b0c068005018488ca60020033300b003002a400080088896600200510018994c004012603a00732337006eb4c06800800cdd7180c000a008301b0024065222323322330020020012259800800c00e2646644b30013372200e00515980099b8f0070028800c01901a44cc014014c08001101a1bae3019001375a6034002603800280d0cc03001000c520004888888c8cc8966002602a005132325980099b88480000062b30013017301d3754660106eb0c084c078dd5005180a998101ba901b33020375003497ae08992cc004c08c00626464b300130250018991919912cc004c05cdd698141814801c4c966002602a604a6ea8006264660240022b3001301900a8acc004c06660026eacc074c09cdd5009c02e91010642465254525900403d15980099b8f00300b8acc004cdc7a44106424652545259000048acc004cdd7981518139baa008301e33029301533029375201697ae0330294c0103d87a80004bd704566002602e6e34dd7181518139baa0018980b9b8d375c6036604e6ea800629410254528204a8a50409514a0812a29410254528204a3029302637540031640906030604a6ea801a2c8118dd718130009bae3026002302600137586048003164088646600200264660020026eacc058c088dd5001912cc004006297adef6c608994c004dd71811800cdd59812000cc0a00092225980099b91489000038acc004cdc7a441000038800c401502544cc0a4cdd81ba9003374c0046600c00c0028128604c0028120896600200314bd7044c8cc88cc88cc00800800489660020031003899198151ba73302a375200a66054604e00266054605000297ae033003003302c002302a00140a06eacc09400cdd718110009980180198138011812800a04630220018b20403301637586022603c6ea80288cdd79811180f9baa3022301f3754002601a660426ea400d2f5c11640711598009807800c4c03e60026eacc050c078dd5005400a91010642465254525900401914a080e101c198031bab3013301d37540120026eb8c07cc070dd5001c566002601c0051323322332259800980d000c4c8c966002604e0050048b2048375a604a00260426ea801a2b3001301300189919194c004dd69813800cdd69813801cdd718138012444b3001302b0048044590280c09c004c098004c084dd50034566002602000315980098109baa00680145902245901f203e407c264b30013019301f37540031323259800980a18109baa0018992cc004c070c088dd5002c4c966002602d30013756603060486ea8c060c090dd5002400a9110642465254525900403113232329800911192cc004cdc42400130013756603e60566ea8c07cc0acdd5000c00e9110642494643464700404d13259800980d98159baa001898161baa302f302c37540031640a8603c60566ea8c07cc0acdd5000c59029198021bac301e302a37540060033026375401922232598009817800c4c96600266ebcc0bcc0b0dd5000981798161baa3020302c375400715980099baf3020302c3754002604060586ea8c080c0b0dd5001c4c966002603860586ea80062646603200220026060605a6ea80062c8158c07cc0b0dd5000c5902a45902a1817000c5902c198111bac301d302a3754006466ebcc0b8c0acdd5181718159baa00130193302d375200697ae04889660026032005159800980dcc004dd5981018151baa016812d2201064249464346470040491301b98009bab3020302a375402d008a450642465254525900404914a081422b30013023002899912cc0066002604a6602a6eacc088c0b0dd500c000d28528a0548acc004c09660026eacc088c0b0dd500c4006911087265672d726f6f74004051159800980e1b8d375c605e60586ea800a266e3cdd7181018161baa002375c604060586ea8026294102a452820548a5040a9300101680440290011bae33004980080b40966eb4c0b4c0a8dd5007a0064804a26645300130300029bad302f0029bae3020302c375400291119912cc004c084dc6801c56600266e3cdd7181a18189baa006375c606860626ea803a2b300198009bae30253031375401d0018012ed514a3198009bae3300b980080ec0b26eb4c0d0c0d401500a2402d0018012ed4817a294102f4528205e375c60640066e48cdc519b8a3371466e2922110626966726f73742d7570646174652d7900375c6064605e6ea804a600294290044dd6981198179baa0125e4a60029469008400979200118151baa00f980080b402201480090282050112cc004cdc4a40000031330030020018b204c3001001222598009810000c4c0a800a3300100398158014cdc0240020028019025459022181318119baa0058b2042375c604a60446ea80062c8100c090c084dd5181218109baa301530213754002604660406ea80062c80f0cc024dd61811180f9baa00b002301e375400860400026040604200260386ea800e294101a203430193754002603a00e6038603a00c452689b2b200801" + } + ] +} diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index a80a60b..10e1afd 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -55,7 +55,14 @@ binocular { } bridge { - plutus-json = "../../FluidTokens/ft-bifrost-bridge/onchain/plutus.json" + # The ft-bifrost-bridge contracts release this bridge was deployed with: "rev5.5" or + # "rev5.6". A property of the bridge, fixed at genesis — a registry revision does not change + # it. See docs/operator-guide.md. + contracts = "rev5.5" + contracts = ${?BIFROST_CONTRACTS} + # An on-disk blueprint replacing the packaged one, for developing the Aiken validators. Empty + # uses the blueprint packaged for `contracts`. Refused when set but unreadable. + plutus-json = "" plutus-json = ${?BIFROST_PLUTUS_JSON} config-nft-policy-id = "00000000000000000000000000000000000000000000000000000000" config-nft-policy-id = ${?CONFIG_NFT_POLICY_ID} diff --git a/src/main/scala/binocular/cli/commands/BootstrapBridgeStateCommand.scala b/src/main/scala/binocular/cli/commands/BootstrapBridgeStateCommand.scala index f45bd7e..14c04ab 100644 --- a/src/main/scala/binocular/cli/commands/BootstrapBridgeStateCommand.scala +++ b/src/main/scala/binocular/cli/commands/BootstrapBridgeStateCommand.scala @@ -78,7 +78,7 @@ case class BootstrapBridgeStateCommand( val sponsorAddress = setup.sponsorAddress val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) diff --git a/src/main/scala/binocular/cli/commands/ConfirmTmtxCommand.scala b/src/main/scala/binocular/cli/commands/ConfirmTmtxCommand.scala index 856ca63..4cb766c 100644 --- a/src/main/scala/binocular/cli/commands/ConfirmTmtxCommand.scala +++ b/src/main/scala/binocular/cli/commands/ConfirmTmtxCommand.scala @@ -103,10 +103,11 @@ case class ConfirmTmtxCommand(dryRun: Boolean = false, notifier: Option[Notifier // The bridge_state validator takes (TM script hash, one-shot ref). Its hash must equal // Config field 3 (`bridge_state_policy`), which is checked against the live config each // cycle. Defaults to the blueprint vendored in binocular's own jar, so a Docker image or a - // systemd unit with no sibling ft checkout still starts. `bridge.plutus-json` / - // BIFROST_PLUTUS_JSON overrides it when the file exists (development). + // systemd unit with no sibling ft checkout still starts. `bridge.contracts` picks the + // release; `bridge.plutus-json` / BIFROST_PLUTUS_JSON overrides it with a file, which must + // then exist (development). val (bridgeBlueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) diff --git a/src/main/scala/binocular/cli/commands/DeployBridgeCommand.scala b/src/main/scala/binocular/cli/commands/DeployBridgeCommand.scala index 93cb65d..fa3e7db 100644 --- a/src/main/scala/binocular/cli/commands/DeployBridgeCommand.scala +++ b/src/main/scala/binocular/cli/commands/DeployBridgeCommand.scala @@ -142,12 +142,13 @@ case class DeployBridgeCommand( val oraclePolicyId = setup.script.scriptHash val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) } Console.info("blueprint", blueprintSource) + Console.info("contracts", s"${blueprint.release.label} (bridge.contracts)") def refOf(u: Utxo): TxOutRef = TxOutRef(TxId(u.input.transactionId), u.input.index) @@ -632,7 +633,11 @@ case class DeployBridgeCommand( .mint(cpiContract.script, Map(cpiAsset -> 1L), Data.unit) .mint(bssContract.script, Map(bssAsset -> 1L), Data.unit) // config UTxO first (config.ak::mint reads self.outputs[0]). - .payTo(configContract.address(network), configValue, configDatum.toData) + .payTo( + configContract.address(network), + configValue, + DeployBridgeCommand.genesisConfigData(configDatum, blueprint.release) + ) .payTo(cpiContract.address(network), cpiValue, cpiDatum.toData) .payTo(bssAddress, bssValue, bssDatum) // Register the withdraw reward accounts here (deposit-less Shelley RegCert, no @@ -786,6 +791,19 @@ case class DeployBridgeCommand( } object DeployBridgeCommand { + + /** The Config datum genesis writes, in the arity of `release` ([[ContractsRelease]]). + * + * Rev 5.6's `config.ak` genesis mint casts the full fourteen-field datum, so #13 + * (`previous_spos_registry_policy_id`, spec [CFG-10]) must be present — empty, since no + * migration is in progress at genesis. Rev 5.5's casts thirteen. + */ + def genesisConfigData(config: ConfigDatum, release: ContractsRelease): Data = + release match { + case ContractsRelease.Rev55 => DeployedConfig(config, Nil).toData + case ContractsRelease.Rev56 => DeployedConfig(config, List(Data.B(ByteString.empty))).toData + } + // Confirmation polling budget. The `.await` window MUST exceed the poll's own budget // (`attempts * delayMs`); otherwise the await preempts the poll and throws a TimeoutException at // the same instant the poll would have observed confirmation — a spurious failure on a tx that diff --git a/src/main/scala/binocular/cli/commands/DeployScriptRefsCommand.scala b/src/main/scala/binocular/cli/commands/DeployScriptRefsCommand.scala index 07638d3..005d85e 100644 --- a/src/main/scala/binocular/cli/commands/DeployScriptRefsCommand.scala +++ b/src/main/scala/binocular/cli/commands/DeployScriptRefsCommand.scala @@ -68,7 +68,7 @@ case class DeployScriptRefsCommand(dryRun: Boolean = false) extends Command { val oraclePolicyId = ByteString.fromArray(setup.script.scriptHash.bytes) val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) @@ -184,32 +184,47 @@ case class DeployScriptRefsCommand(dryRun: Boolean = false) extends Command { deployed.params.maxValidityWindowMs ) ) - FederationScripts - .verifyAgainstConfig(federation, deployed) + val standing = FederationScripts + .standing(federation, deployed) .valueOr { err => Console.error(err); break(1) } - Console.info("spos_registry script hash", federation.registry.policyId.toHex) - Console.info("spo_bans script hash", federation.bans.policyId.toHex) - Console.info("(verified against the deployed Config)", "#8 / #9 / #10 / #12") - println() - // treasury_info is NOT published: nothing ever spends it with the script - // inlined at size — its spend paths are small, and the state UTxO is read as a - // reference input everywhere else. - ("spos_registry", federation.registry.script) :: - ("spo_bans", federation.bans.script) :: - FaultVerifierContract.Titles.zipWithIndex.map { case (title, i) => - val label = - List("fault_round1", "fault_round2", "fault_equivocation")(i) - ( - label, - FaultVerifierContract( - blueprint, - title, - ByteString.fromArray(federation.registry.policyId.bytes) - ).script + standing match { + // A registry revision moved #9 and #8 to scripts compiled from fresh one-shots. + // heimdall's revision steps deploy their reference scripts (deploy-registry-ref, + // deploy-fault-ref, deploy-spo-bans-ref); the ones this one-shot compiles to are + // the scripts the bridge left, and publishing them would lock ADA for nothing. + case FederationScripts.Standing.RegistryRevised(registry, bans) => + Console.info( + "federation half", + s"skipped — the Config names a revised registry ${registry.toHex} and ban " + + s"list ${bans.toHex}; heimdall publishes their reference scripts" ) - } + println() + Nil + case FederationScripts.Standing.Genesis => + Console.info("spos_registry script hash", federation.registry.policyId.toHex) + Console.info("spo_bans script hash", federation.bans.policyId.toHex) + Console.info("(verified against the deployed Config)", "#8 / #9 / #10 / #12") + println() + // treasury_info is NOT published: nothing ever spends it with the script + // inlined at size — its spend paths are small, and the state UTxO is read as + // a reference input everywhere else. + ("spos_registry", federation.registry.script) :: + ("spo_bans", federation.bans.script) :: + FaultVerifierContract.Titles.zipWithIndex.map { case (title, i) => + val label = + List("fault_round1", "fault_round2", "fault_equivocation")(i) + ( + label, + FaultVerifierContract( + blueprint, + title, + ByteString.fromArray(federation.registry.policyId.bytes) + ).script + ) + } + } } if dryRun then { diff --git a/src/main/scala/binocular/cli/commands/PegInCompleteCommand.scala b/src/main/scala/binocular/cli/commands/PegInCompleteCommand.scala index 84b78ba..6c08540 100644 --- a/src/main/scala/binocular/cli/commands/PegInCompleteCommand.scala +++ b/src/main/scala/binocular/cli/commands/PegInCompleteCommand.scala @@ -100,7 +100,7 @@ case class PegInCompleteCommand( val oracleScriptHash = setup.script.scriptHash val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) diff --git a/src/main/scala/binocular/cli/commands/PegInRequestCommand.scala b/src/main/scala/binocular/cli/commands/PegInRequestCommand.scala index 17577e0..9e5c412 100644 --- a/src/main/scala/binocular/cli/commands/PegInRequestCommand.scala +++ b/src/main/scala/binocular/cli/commands/PegInRequestCommand.scala @@ -58,7 +58,7 @@ case class PegInRequestCommand( val oraclePolicyId = setup.script.scriptHash val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) diff --git a/src/main/scala/binocular/cli/commands/PegOutCompleteCommand.scala b/src/main/scala/binocular/cli/commands/PegOutCompleteCommand.scala index fb2d659..8dead5c 100644 --- a/src/main/scala/binocular/cli/commands/PegOutCompleteCommand.scala +++ b/src/main/scala/binocular/cli/commands/PegOutCompleteCommand.scala @@ -54,7 +54,7 @@ case class PegOutCompleteCommand(pegOut: Option[String] = None, dryRun: Boolean val oracleScriptHashBS = ByteString.fromArray(setup.script.scriptHash.bytes) val (bridgeBlueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) diff --git a/src/main/scala/binocular/cli/commands/PegOutRequestCommand.scala b/src/main/scala/binocular/cli/commands/PegOutRequestCommand.scala index 70a4208..b39d4c0 100644 --- a/src/main/scala/binocular/cli/commands/PegOutRequestCommand.scala +++ b/src/main/scala/binocular/cli/commands/PegOutRequestCommand.scala @@ -107,7 +107,7 @@ case class PegOutRequestCommand( val oraclePolicyId = ByteString.fromArray(setup.script.scriptHash.bytes) val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) diff --git a/src/main/scala/binocular/cli/commands/RegisterBridgeCredsCommand.scala b/src/main/scala/binocular/cli/commands/RegisterBridgeCredsCommand.scala index 7ce1a69..bd7ac96 100644 --- a/src/main/scala/binocular/cli/commands/RegisterBridgeCredsCommand.scala +++ b/src/main/scala/binocular/cli/commands/RegisterBridgeCredsCommand.scala @@ -89,7 +89,7 @@ case class RegisterBridgeCredsCommand(dryRun: Boolean = false) extends Command { val oraclePolicyId = ByteString.fromArray(setup.script.scriptHash.bytes) val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) @@ -157,11 +157,23 @@ case class RegisterBridgeCredsCommand(dryRun: Boolean = false) extends Command { ) ) FederationScripts - .verifyAgainstConfig(federation, deployed) + .standing(federation, deployed) .valueOr { err => Console.error(err); break(1) - } - List("spo_bans" -> federation.bans.policyId) + } match { + case FederationScripts.Standing.Genesis => + List("spo_bans" -> federation.bans.policyId) + // The revised ban list is heimdall's to register (`init-scripts`), with + // the fault policies of the revised registry; the one this one-shot + // compiles to is the list the bridge no longer reads. + case FederationScripts.Standing.RegistryRevised(_, bans) => + Console.info( + "spo_bans", + s"skipped — the Config names a revised ban list ${bans.toHex}; " + + "heimdall init-scripts registers its credential" + ) + Nil + } } val creds: List[(String, ScriptHash)] = List( diff --git a/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala b/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala index fea3e10..211e8e9 100644 --- a/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala +++ b/src/main/scala/binocular/cli/commands/UpdateConfigCommand.scala @@ -126,7 +126,7 @@ case class UpdateConfigCommand( break(1) } val (blueprint, blueprintSource) = - try BifrostBlueprint.resolve(config.bridge.plutusJson) + try BifrostBlueprint.forBridge(config.bridge) catch { case e: Exception => Console.error(s"Loading bridge blueprint: ${e.getMessage}"); break(1) @@ -144,7 +144,7 @@ case class UpdateConfigCommand( Console.error( s"Derived config policy ${configContract.policyId.toHex} does not match " + s"bridge.config-nft-policy-id ${config.bridge.configNftPolicyId} — check the " + - "one-shot ref and plutus.json" + "one-shot ref and bridge.contracts (the release this bridge was deployed with)" ) break(1) } diff --git a/src/main/scala/binocular/traffic/LiveTraffic.scala b/src/main/scala/binocular/traffic/LiveTraffic.scala index 138eeb7..d85dc79 100644 --- a/src/main/scala/binocular/traffic/LiveTraffic.scala +++ b/src/main/scala/binocular/traffic/LiveTraffic.scala @@ -42,7 +42,7 @@ final class LiveTraffic(config: BinocularConfig, notifier: Notifier)(using Execu ) private val qAuth = wallet.identity.outputKey private val fundingScript = ByteString.fromArray(wallet.funding.scriptPubKey.toArray) - private val blueprint = BifrostBlueprint.resolve(config.bridge.plutusJson)._1 + private val blueprint = BifrostBlueprint.forBridge(config.bridge)._1 private val configPolicy = ScriptHash.fromHex(config.bridge.configNftPolicyId) private val configAsset = AssetName(ByteString.fromHex(config.bridge.configNftAssetName)) private val configBytes = ByteString.fromArray(configPolicy.bytes) diff --git a/src/main/scala/binocular/watchtower/BifrostContracts.scala b/src/main/scala/binocular/watchtower/BifrostContracts.scala index c4c7a5b..c6b7383 100644 --- a/src/main/scala/binocular/watchtower/BifrostContracts.scala +++ b/src/main/scala/binocular/watchtower/BifrostContracts.scala @@ -10,6 +10,45 @@ import scalus.uplc.builtin.Data.{toData, FromData, ToData} import java.nio.file.{Files, Paths} +/** The ft-bifrost-bridge contracts release a bridge was DEPLOYED with — `bridge.contracts`. + * + * A property of the bridge, fixed at genesis, and not of this binary: a running bridge keeps the + * `config.ak`, peg and TM scripts it was deployed with, because the Config is updated in place and + * never redeployed. A registry revision does not change it either. It replaces the registry and + * the ban list, which heimdall deploys, and binocular reads their new policy ids from the Config + * (#8, #9) rather than deriving them. + * + * What differs between the two, for what binocular derives: + * - `config.ak`: same parameters, different code (rev 5.6's genesis mint casts a 14-field datum), + * so a different Config policy id. + * - `spos_registry`: rev 5.6 adds the Config NFT policy as a fourth parameter ([MIG-1] reads #13 + * through it). + * - `spo_bans`: its first parameter is the registry policy in rev 5.5 and the Config NFT policy + * in rev 5.6 ([PRE-5]). + * - the Config datum a genesis writes: 13 fields, or 14 with #13 empty ([CFG-10]). + * + * @param configFieldCount + * the arity of the Config datum a genesis under this release writes. + */ +enum ContractsRelease(val label: String, val resource: String, val configFieldCount: Int) { + case Rev55 extends ContractsRelease("rev5.5", "/bifrost-plutus-min.json", 13) + case Rev56 extends ContractsRelease("rev5.6", "/bifrost-plutus-min-rev5.6.json", 14) +} + +object ContractsRelease { + + /** Parse `bridge.contracts`. An unknown value is an error, never a default: the two releases + * derive different policy ids for the same bridge. + */ + def parse(value: String): Either[String, ContractsRelease] = + values + .find(_.label == value.trim) + .toRight( + s"bridge.contracts = '$value' is not a contracts release this binocular knows " + + s"(${values.map(_.label).mkString(", ")})" + ) +} + /** Reads ft-bifrost-bridge Aiken validators from a CIP-57 `plutus.json` blueprint. * * Parameter application mirrors `aiken blueprint apply` / Blaze `applyParamsToScript`: each @@ -17,7 +56,13 @@ import java.nio.file.{Files, Paths} * `ByteArray` params used here that is `Data.B(bytes)`, which is exactly what Scalus's * `Program.$(data: Data)` produces. */ -final class BifrostBlueprint(json: ujson.Value) { +final class BifrostBlueprint( + json: ujson.Value, + /** The release these validators belong to. It decides how two of them are parameterized (see + * [[ContractsRelease]]), so it travels with the bytes rather than beside them. + */ + val release: ContractsRelease = ContractsRelease.Rev55 +) { /** Single-CBOR `compiledCode` hex for `title` (all handlers of one Aiken validator share it). */ @@ -35,14 +80,17 @@ final class BifrostBlueprint(json: ujson.Value) { object BifrostBlueprint { - /** Classpath path of the blueprint vendored into binocular's own jar. */ - val PackagedResource = "/bifrost-plutus-min.json" + /** Classpath path of the rev-5.5 blueprint vendored into binocular's own jar. */ + val PackagedResource: String = ContractsRelease.Rev55.resource - def fromFile(path: String): BifrostBlueprint = - fromString(Files.readString(Paths.get(path))) + def fromFile(path: String, release: ContractsRelease = ContractsRelease.Rev55): BifrostBlueprint = + fromString(Files.readString(Paths.get(path)), release) - def fromString(json: String): BifrostBlueprint = - new BifrostBlueprint(ujson.read(json)) + def fromString( + json: String, + release: ContractsRelease = ContractsRelease.Rev55 + ): BifrostBlueprint = + new BifrostBlueprint(ujson.read(json), release) /** The blueprint vendored as a jar resource: the `compiledCode` of every ft-bifrost-bridge * validator binocular applies parameters to, copied byte for byte from @@ -68,32 +116,48 @@ object BifrostBlueprint { * Refresh with a straight copy of the `compiledCode` fields from ft's `plutus.json`, then move * the affected pins in the same commit. */ - def packaged: BifrostBlueprint = { - val stream = getClass.getResourceAsStream(PackagedResource) + def packaged: BifrostBlueprint = packaged(ContractsRelease.Rev55) + + /** The blueprint of `release`, vendored as a jar resource. */ + def packaged(release: ContractsRelease): BifrostBlueprint = { + val stream = getClass.getResourceAsStream(release.resource) if stream == null then throw new IllegalStateException( - s"Blueprint resource $PackagedResource not found on the classpath — the jar is built wrong" + s"Blueprint resource ${release.resource} not found on the classpath — the jar is built wrong" ) - try fromString(scala.io.Source.fromInputStream(stream).mkString) + try fromString(scala.io.Source.fromInputStream(stream).mkString, release) finally stream.close() } - /** Resolve the blueprint to use, preferring an on-disk override. + /** The blueprint of `release`: the vendored one, or `path` when it is set. * - * `path` is `bridge.plutus-json` (env `BIFROST_PLUTUS_JSON`), whose default points at a - * sibling ft checkout. When that file EXISTS it wins, so a developer working on the Aiken - * validators sees their edits immediately. When it does not — the normal state of a deployed - * image — the [[packaged]] resource is used, and startup succeeds. + * `path` is `bridge.plutus-json` (env `BIFROST_PLUTUS_JSON`), an override for a developer + * working on the Aiken validators. It is empty by default and must name a readable file when + * set. It used to default to a sibling ft checkout and fall back silently when that was + * absent, which made the contracts a command built with depend on whether, and on which + * branch, such a checkout happened to sit next to the working directory. * * Returns the blueprint and a human-readable description of where it came from, so every - * command can log which one it used instead of leaving it ambiguous. + * command can log which one it used. */ - def resolve(path: String): (BifrostBlueprint, String) = { + def resolve(release: ContractsRelease, path: String): (BifrostBlueprint, String) = { val trimmed = Option(path).map(_.trim).getOrElse("") - if trimmed.nonEmpty && Files.isReadable(Paths.get(trimmed)) then - (fromFile(trimmed), trimmed) - else (packaged, s"packaged $PackagedResource") + if trimmed.isEmpty then (packaged(release), s"packaged ${release.label} ${release.resource}") + else if Files.isReadable(Paths.get(trimmed)) then + (fromFile(trimmed, release), s"$trimmed (as ${release.label})") + else + throw new IllegalArgumentException( + s"bridge.plutus-json = '$trimmed' is not readable. It is an override, and an override " + + "that cannot be read is refused rather than replaced by the packaged blueprint" + ) } + + /** [[resolve]] for a bridge's configuration: its `contracts` release and `plutus-json`. */ + def forBridge(bridge: BridgeConfig): (BifrostBlueprint, String) = + ContractsRelease.parse(bridge.contracts) match { + case Right(release) => resolve(release, bridge.plutusJson) + case Left(err) => throw new IllegalArgumentException(err) + } } /** The `peg_in_validator` parameterized with its on-chain params. The script hash is the peg-in NFT @@ -348,14 +412,20 @@ object FederationScripts { val treasury = TreasuryInfoContract(blueprint, federationTxId, federationIndex, configPolicyId) val treasuryPolicy = ByteString.fromArray(treasury.policyId.bytes) - val registry = - SposRegistryContract(blueprint, federationTxId, federationIndex, treasuryPolicy) + val registry = SposRegistryContract( + blueprint, + federationTxId, + federationIndex, + treasuryPolicy, + configPolicyId + ) val registryPolicy = ByteString.fromArray(registry.policyId.bytes) val faultPolicies = FaultVerifierContract.all(blueprint, registryPolicy) val (baseBanDurationMs, maxFaultsBeforePermanent, maxValidityWindowMs) = banSchedule val bans = SpoBansContract( blueprint, registryPolicy, + configPolicyId, faultPolicies, baseBanDurationMs = baseBanDurationMs, maxFaultsBeforePermanent = maxFaultsBeforePermanent, @@ -366,6 +436,38 @@ object FederationScripts { FederationScripts(treasury, registry, faultPolicies, bans) } + /** How a derivation from the federation one-shot stands against the deployed Config. + * + * `Genesis`: all three policies are the ones this one-shot compiles to, as deployed. + * `RegistryRevised`: the treasury still is, but #9 is not — a registry revision has moved #9 + * and #8 to scripts compiled from fresh one-shots, which heimdall deploys and which binocular + * therefore does not publish or register. A wrong one-shot fails the treasury too, so it is + * still an error, as is a ban list that disagrees while the registry does not. + */ + enum Standing { + case Genesis + case RegistryRevised(sposRegistryPolicyId: ByteString, spoBansPolicyId: ByteString) + } + + def standing(scripts: FederationScripts, config: ConfigDatum): Either[String, Standing] = { + def same(derived: ScriptHash, published: ByteString) = derived.toHex == published.toHex + if !same(scripts.treasury.policyId, config.treasuryInfoPolicyId) then + Left( + s"derived treasury_info policy ${scripts.treasury.policyId.toHex} does not match the " + + s"Config's ${config.treasuryInfoPolicyId.toHex} — this is not the outpoint the " + + "bridge was deployed from, or bridge.contracts is not the release it was deployed with" + ) + else if !same(scripts.registry.policyId, config.sposRegistryPolicyId) then + Right(Standing.RegistryRevised(config.sposRegistryPolicyId, config.spoBansPolicyId)) + else if !same(scripts.bans.policyId, config.spoBansPolicyId) then + Left( + s"derived spo_bans policy ${scripts.bans.policyId.toHex} does not match the Config's " + + s"${config.spoBansPolicyId.toHex} although the registry does — the ban schedule " + + "must be read from the deployed Config, not from local settings" + ) + else Right(Standing.Genesis) + } + /** Check a derivation against what the deployed Config publishes (#8 bans, #9 registry, #10 * treasury). * @@ -423,17 +525,23 @@ object SposRegistryContract { blueprint: BifrostBlueprint, bootstrapTxId: ByteString, bootstrapIndex: BigInt, - treasuryPolicyId: ByteString + treasuryPolicyId: ByteString, + configPolicyId: ByteString ): SposRegistryContract = { // spec [REG-6]: the third parameter is the Treasury state policy this registry PINS. It // could not have been a parameter before rev 5.5 — treasury_info took registry_policy_id, // so the dependency was a cycle — and without it the registry located the Treasury state // UTxO by redeemer index with no authentication at all. - val applied = Program + val base = Program .fromCborHex(blueprint.compiledCode(ValidatorTitle)) .$(Data.B(bootstrapTxId)) .$(Data.I(bootstrapIndex)) .$(Data.B(treasuryPolicyId)) + // Rev 5.6 adds the Config NFT policy: its `Migrate` branch reads Config #13 ([MIG-1]). + val applied = blueprint.release match { + case ContractsRelease.Rev55 => base + case ContractsRelease.Rev56 => base.$(Data.B(configPolicyId)) + } SposRegistryContract(Script.PlutusV3(applied.cborByteString)) } } @@ -603,6 +711,7 @@ object SpoBansContract { def apply( blueprint: BifrostBlueprint, sposRegistryPolicyId: ByteString, + configPolicyId: ByteString, faultProofPolicyIds: List[ByteString], baseBanDurationMs: BigInt, maxFaultsBeforePermanent: BigInt, @@ -618,9 +727,16 @@ object SpoBansContract { require(baseBanDurationMs > 0, "base_ban_duration_ms must be > 0") require(maxFaultsBeforePermanent > 0, "max_faults_before_permanent must be > 0") require(maxValidityWindowMs >= 0, "max_validity_window_ms must be >= 0") + // The first parameter is what `spo_bans` learns the registry THROUGH: the registry policy + // itself in rev 5.5, the Config NFT policy in rev 5.6, which reads #9 at run time + // ([PRE-5]). + val identity = blueprint.release match { + case ContractsRelease.Rev55 => sposRegistryPolicyId + case ContractsRelease.Rev56 => configPolicyId + } val applied = Program .fromCborHex(blueprint.compiledCode(ValidatorTitle)) - .$(Data.B(sposRegistryPolicyId)) + .$(Data.B(identity)) // Indefinite-length array — see the note on [[SposRegistryContract]]. .$(Data.List(PList.from(faultProofPolicyIds.map(p => Data.B(p): Data)))) .$(Data.I(baseBanDurationMs)) diff --git a/src/main/scala/binocular/watchtower/BridgeConfig.scala b/src/main/scala/binocular/watchtower/BridgeConfig.scala index 88aed2e..ea10dbc 100644 --- a/src/main/scala/binocular/watchtower/BridgeConfig.scala +++ b/src/main/scala/binocular/watchtower/BridgeConfig.scala @@ -31,7 +31,15 @@ case class BanScheduleConfig( ) case class BridgeConfig( - plutusJson: String = "../../FluidTokens/ft-bifrost-bridge/onchain/plutus.json", + // The ft-bifrost-bridge contracts release this bridge was DEPLOYED with: "rev5.5" or "rev5.6" + // (see ContractsRelease). Fixed at genesis — a running bridge keeps its config/peg/TM scripts + // for good, and a registry revision does not change it either: the revised registry and ban + // list are heimdall's, and binocular reads their ids from the Config. + contracts: String = "rev5.5", + // An on-disk blueprint that replaces the packaged one of `contracts`, for a developer working + // on the Aiken validators. Empty = packaged. Must be readable when set: an override that + // silently falls back is an override nobody can rely on. + plutusJson: String = "", configNftPolicyId: String = "00000000000000000000000000000000000000000000000000000000", configNftAssetName: String = "", bridgedTokenPolicyId: String = "00000000000000000000000000000000000000000000000000000000", diff --git a/src/test/scala/binocular/BifrostContractsTest.scala b/src/test/scala/binocular/BifrostContractsTest.scala index a69fecb..94be150 100644 --- a/src/test/scala/binocular/BifrostContractsTest.scala +++ b/src/test/scala/binocular/BifrostContractsTest.scala @@ -274,8 +274,11 @@ class BifrostContractsTest extends AnyFunSuite { ) case Some(path) => val ft = BifrostBlueprint.fromFile(path.toString) - val stale = - blueprint.validatorTitles.filterNot(RebuildDrift.contains).filter { title => + // Two releases are vendored, and the ft checkout may be on either — main, or the + // branch of the next release. It must match ONE of them exactly; a checkout that + // matches neither means a vendored copy is stale. + def staleAgainst(vendored: BifrostBlueprint): Seq[String] = + vendored.validatorTitles.filterNot(RebuildDrift.contains).filter { title => val ftCode = try ft.compiledCode(title) catch { @@ -285,13 +288,106 @@ class BifrostContractsTest extends AnyFunSuite { "the two blueprints no longer describe the same bridge" ) } - ftCode != blueprint.compiledCode(title) + ftCode != vendored.compiledCode(title) } + val byRelease = ContractsRelease.values.toList.map { r => + r -> staleAgainst(BifrostBlueprint.packaged(r)) + } assert( - stale.isEmpty, - s"vendored compiledCode is stale against $path for: ${stale.mkString(", ")} " + - "– re-vendor bifrost-plutus-min.json" + byRelease.exists(_._2.isEmpty), + s"the ft checkout at $path matches no vendored release — " + + byRelease + .map { case (r, st) => s"${r.label} differs in ${st.mkString(", ")}" } + .mkString("; ") + + ". Re-vendor the release that checkout is on" ) } } + + // --- bridge.contracts and bridge.plutus-json --- + + test("bridge.contracts names a vendored release, and an unknown one is an error") { + assert(ContractsRelease.parse("rev5.5") == Right(ContractsRelease.Rev55)) + assert(ContractsRelease.parse(" rev5.6 ") == Right(ContractsRelease.Rev56)) + assert(ContractsRelease.parse("rev5.7").isLeft) + // Each release's vendored blueprint loads, and carries its release. + ContractsRelease.values.foreach { r => + assert(BifrostBlueprint.packaged(r).release == r) + } + } + + // The releases differ in exactly the three validators rev 5.6 changed. The Config policy moves + // with config.ak, which is what lets a command tell the release a Config was deployed with. + test("the vendored releases differ in config, spos_registry and spo_bans only") { + val a = BifrostBlueprint.packaged(ContractsRelease.Rev55) + val b = BifrostBlueprint.packaged(ContractsRelease.Rev56) + val differ = a.validatorTitles.filter(t => a.compiledCode(t) != b.compiledCode(t)).toSet + assert( + differ == Set( + "bitcoin/config.config.mint", + "bitcoin/spos_registry.spo_registry.mint", + "bitcoin/spo_bans.spo_bans.mint" + ) + ) + } + + test("an empty plutus-json uses the packaged release; an unreadable one is refused") { + val (bp, source) = BifrostBlueprint.resolve(ContractsRelease.Rev56, "") + assert(bp.release == ContractsRelease.Rev56) + assert(source.contains("rev5.6")) + // It used to fall back to the packaged blueprint silently, so the contracts a command + // built with depended on whether a sibling checkout existed. + intercept[IllegalArgumentException]( + BifrostBlueprint.resolve(ContractsRelease.Rev55, "/nonexistent/plutus.json") + ) + } + + // Rev 5.6's genesis mint casts the fourteen-field datum, so genesis must write #13 — empty. + test("genesis writes the Config arity of its release") { + val cfg = ConfigDatum( + updateAuth = scalus.cardano.onchain.plutus.prelude.Option.None, + params = ConfigParams( + schedule = ScheduleParams( + BigInt(3600), + BigInt(7200), + BigInt(10800), + BigInt(21600), + BigInt(1800), + BigInt(1800), + BigInt(600), + BigInt(129600), + BigInt(345600), + BigInt(129600) + ), + feeRateSatPerVb = BigInt(1), + perPegoutFee = BigInt(1000), + minPegOutFbtc = BigInt(10000), + baseBanDurationMs = BigInt(600000), + maxFaultsBeforePermanent = BigInt(3), + maxValidityWindowMs = BigInt(3600000), + federationCsvBlocks = BigInt(144), + peginRefundTimeoutBlocks = BigInt(720) + ), + bridgedTokenPolicy = ByteString.empty, + completedPegInsPolicy = ByteString.empty, + bridgeStatePolicy = ByteString.empty, + tmScriptHash = ByteString.empty, + pegInScriptHash = ByteString.empty, + pegOutScriptHash = ByteString.empty, + spoBansPolicyId = ByteString.empty, + sposRegistryPolicyId = ByteString.empty, + treasuryInfoPolicyId = ByteString.empty, + yFederation = ByteString.empty, + federationOneShot = TxOutRef(TxId(ByteString.fromHex("c3" * 32)), BigInt(0)) + ) + def arity(d: scalus.uplc.builtin.Data) = d match { + case scalus.uplc.builtin.Data.Constr(0, fs) => fs.asScala.toList + case other => fail(s"not a Constr 0: $other") + } + import binocular.cli.commands.DeployBridgeCommand.genesisConfigData + assert(arity(genesisConfigData(cfg, ContractsRelease.Rev55)).size == 13) + val f56 = arity(genesisConfigData(cfg, ContractsRelease.Rev56)) + assert(f56.size == 14) + assert(f56(13) == scalus.uplc.builtin.Data.B(ByteString.empty)) + } } diff --git a/src/test/scala/binocular/FederationContractsTest.scala b/src/test/scala/binocular/FederationContractsTest.scala index 57297ac..7791404 100644 --- a/src/test/scala/binocular/FederationContractsTest.scala +++ b/src/test/scala/binocular/FederationContractsTest.scala @@ -37,7 +37,13 @@ class FederationContractsTest extends AnyFunSuite { private def treasuryPolicyForTest = ByteString.fromArray(treasuryInfo.policyId.bytes) private def registry = - SposRegistryContract(blueprint, oneShot, oneShotIndex, treasuryPolicyForTest) + SposRegistryContract( + blueprint, + oneShot, + oneShotIndex, + treasuryPolicyForTest, + configPolicyForTest + ) private def registryPolicy = ByteString.fromArray(registry.policyId.bytes) test("spos_registry policy matches heimdall's derivation") { @@ -69,6 +75,7 @@ class FederationContractsTest extends AnyFunSuite { val bans = SpoBansContract( blueprint, registryPolicy, + configPolicyForTest, FaultVerifierContract.all(blueprint, registryPolicy), baseBanDurationMs = BigInt(600000), maxFaultsBeforePermanent = BigInt(3), @@ -86,6 +93,7 @@ class FederationContractsTest extends AnyFunSuite { def bans(policies: List[ByteString]) = SpoBansContract( blueprint, registryPolicy, + configPolicyForTest, policies, BigInt(600000), BigInt(3), @@ -103,6 +111,7 @@ class FederationContractsTest extends AnyFunSuite { def bans(base: BigInt, maxFaults: BigInt, window: BigInt) = SpoBansContract( blueprint, registryPolicy, + configPolicyForTest, policies, base, maxFaults, @@ -121,6 +130,7 @@ class FederationContractsTest extends AnyFunSuite { def build(policies: List[ByteString]) = SpoBansContract( blueprint, registryPolicy, + configPolicyForTest, policies, BigInt(600000), BigInt(3), @@ -167,7 +177,8 @@ class FederationContractsTest extends AnyFunSuite { blueprint, ByteString.fromHex("cc" * 32), oneShotIndex, - treasuryPolicyForTest + treasuryPolicyForTest, + configPolicyForTest ) val otherPolicy = ByteString.fromArray(other.policyId.bytes) assert(other.policyId.toHex != registry.policyId.toHex) @@ -277,4 +288,87 @@ class FederationContractsTest extends AnyFunSuite { ) assert(FederationScripts.verifyAgainstConfig(other, configFor(derived)).isLeft) } + + // --- rev 5.6 --- + // + // The same inputs through the rev-5.6 blueprint (ft 096f76c, the one heimdall embeds). Every + // hash below was derived by heimdall's Rust from those bytes, so these pin binocular's two + // version-dependent parameterizations — the registry's added Config policy and the ban list's + // Config policy in place of the registry hash — against an independent implementation. + + private val rev56 = BifrostBlueprint.packaged(ContractsRelease.Rev56) + + private def derived56 = FederationScripts.derive( + rev56, + oneShot, + oneShotIndex, + configPolicyForTest, + (BigInt(600000), BigInt(3), BigInt(3600000)) + ) + + test("rev 5.6: FederationScripts.derive matches heimdall's derivation") { + val f = derived56 + // treasury_info did not change between the releases, so neither did its policy. + assert( + f.treasury.policyId.toHex == "935993611500f483c71ef16964698ebfc4f4f2ae5f92719331418db5" + ) + assert( + f.registry.policyId.toHex == "90bbf858a6d699e5a82b3b5c7e2f7ac8960c1908743cfde129496d12" + ) + assert( + f.faultPolicies.map(_.toHex) == List( + "4fecea15ff61fb722fb3f084444d671e45c7d07c8931bb6e14fce1da", + "ae0e4fa378bf2f027dc2a146ec067e9c5c76e8431e31d4cd1d03020e", + "84f9bac4cc2c8fc0d63fe1ea564f3c28bc49d95c06e2563efe88dae2" + ) + ) + assert(f.bans.policyId.toHex == "6abf2d55cc123885a09c6c3bdcddd801f8822e827db164af736a72e0") + } + + // --- standing after a registry revision --- + + test("standing: the Config genesis wrote is Genesis") { + assert(FederationScripts.standing(derived, configFor(derived)) == Right(FederationScripts.Standing.Genesis)) + } + + // After a revision #9 and #8 name scripts compiled from fresh one-shots. The treasury is never + // revised, so a matching #10 says the one-shot is right and the moved registry is a revision, + // not a mistake — and binocular leaves those scripts to heimdall. + test("standing: a moved registry with the treasury intact is a revision, not an error") { + val revised = configFor(derived).copy( + sposRegistryPolicyId = ByteString.fromHex("a1" * 28), + spoBansPolicyId = ByteString.fromHex("a2" * 28) + ) + assert( + FederationScripts.standing(derived, revised) == Right( + FederationScripts.Standing.RegistryRevised( + ByteString.fromHex("a1" * 28), + ByteString.fromHex("a2" * 28) + ) + ) + ) + } + + test("standing: a wrong one-shot still fails, on the treasury") { + val wrong = FederationScripts.derive( + blueprint, + ByteString.fromHex("cc" * 32), + oneShotIndex, + configPolicyForTest, + (BigInt(600000), BigInt(3), BigInt(3600000)) + ) + val err = FederationScripts.standing(wrong, configFor(derived)).swap.getOrElse(fail("expected a mismatch")) + assert(err.contains("treasury_info")) + } + + test("standing: a ban list that disagrees while the registry agrees is an error") { + val other = FederationScripts.derive( + blueprint, + oneShot, + oneShotIndex, + configPolicyForTest, + (BigInt(600001), BigInt(3), BigInt(3600000)) + ) + assert(FederationScripts.standing(other, configFor(derived)).isLeft) + } } From 7546ece08df29ea7f9a06d2003857ddec489a20d Mon Sep 17 00:00:00 2001 From: Ruslan Shevchenko Date: Wed, 23 Sep 2026 13:36:57 +0300 Subject: [PATCH 3/3] docs: the registry revision is upgrade first, switch later The guide's revision section now gives the order: operators upgrade heimdall at their own pace, the new version runs the unrevised bridge unchanged, and the governance Update comes once every node runs it. --- docs/operator-guide.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/operator-guide.md b/docs/operator-guide.md index 110b19d..479de29 100644 --- a/docs/operator-guide.md +++ b/docs/operator-guide.md @@ -191,9 +191,17 @@ to the ban policy id, so changing it means deploying a new ban list. ### A registry revision A contracts release can replace the SPO registry, and with it the ban list. heimdall carries every -registration across with no cold key. Operators install the new heimdall, and the federation runs -one command for the stragglers. binocular's part is the single governance Update in the middle, -and ending the window afterwards: +registration across with no cold key. The order is **upgrade first, switch later**: + +1. Operators upgrade heimdall at their own pace. The new version runs the unrevised bridge exactly + as the previous one does, so a roster that is half upgraded keeps holding ceremonies. +2. Once every node runs it, the federation deploys the new registry and ban list, and you make the + governance Update below. +3. The nodes see the Update and carry themselves across, and the federation runs one command for + any stragglers. +4. When everyone has crossed, you end the window. + +binocular's part is the Update in the middle, and ending the window afterwards: ```bash binocular --config bridge.conf update-config \