Skip to content

Commit

Permalink
update StagingStatusUpdated.code event value to SHA3_256 hash
Browse files Browse the repository at this point in the history
  • Loading branch information
sisyphusSmiling committed Jul 26, 2024
1 parent 0a0d1d8 commit 446aeb6
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 8 deletions.
21 changes: 19 additions & 2 deletions contracts/MigrationContractStaging.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,15 @@ access(all) contract MigrationContractStaging {
return self.getStagedContractUpdate(address: address, name: name)?.code
}

/// Returns the staged contract code hash for the given address and name or nil if it's not staged
///
access(all) view fun getStagedContractCodeHash(address: Address, name: String): String? {
if let update = self.getStagedContractUpdate(address: address, name: name) {
return self.getCodeHash(update.code)
}
return nil
}

/// Returns the ContractUpdate struct for the given contract if it's been staged.
///
access(all) view fun getStagedContractUpdate(address: Address, name: String): ContractUpdate? {
Expand Down Expand Up @@ -207,6 +216,14 @@ access(all) contract MigrationContractStaging {
?? panic("Could not derive Capsule StoragePath for given address")
}

/* --- Util --- */

/// Returns the hash of the given code, hashing with SHA3-256
///
access(all) fun getCodeHash(_ code: String): String {
return String.encodeHex(HashAlgorithm.SHA3_256.hash(code.utf8))
}

/* ------------------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------ Constructs ------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------------------ */
Expand Down Expand Up @@ -352,7 +369,7 @@ access(all) contract MigrationContractStaging {
emit StagingStatusUpdated(
capsuleUUID: self.uuid,
address: self.update.address,
code: code,
code: MigrationContractStaging.getCodeHash(code),
contract: self.update.name,
action: "replace"
)
Expand Down Expand Up @@ -406,7 +423,7 @@ access(all) contract MigrationContractStaging {
emit StagingStatusUpdated(
capsuleUUID: capsule.uuid,
address: host.address(),
code: code,
code: MigrationContractStaging.getCodeHash(code),
contract: name,
action: "stage"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import "MigrationContractStaging"

#interaction (
version: "1.1.0",
title: "Get Staged Contract Code",
description: "Returns the Cadence code that has been staged for the given contract or nil if it is not yet staged.",
language: "en-US",
)

/// Returns the code hash as it is staged or nil if it not currently staged.
///
access(all) fun main(contractAddress: Address, contractName: String): String? {
return MigrationContractStaging.getStagedContractCodeHash(address: contractAddress, name: contractName)
}
42 changes: 36 additions & 6 deletions tests/migration_contract_staging_tests.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ access(all) let bcAccount = Test.getAccount(0x0000000000000010)
// Content of update contracts as hex strings
access(all) let fooUpdateCode = "61636365737328616c6c2920636f6e747261637420466f6f207b0a2020202061636365737328616c6c292066756e20666f6f28293a20537472696e67207b0a202020202020202072657475726e2022626172220a202020207d0a7d0a"
access(all) let fooUpdateCadence = String.fromUTF8(fooUpdateCode.decodeHex()) ?? panic("Problem decoding fooUpdateCode")
access(all) var fooUpdateHash = ""
access(all) let aUpdateCode = "61636365737328616c6c2920636f6e747261637420696e746572666163652041207b0a202020200a2020202061636365737328616c6c29207265736f7572636520696e746572666163652049207b0a202020202020202061636365737328616c6c292066756e20666f6f28293a20537472696e670a202020202020202061636365737328616c6c292066756e2062617228293a20537472696e670a202020207d0a0a2020202061636365737328616c6c29207265736f757263652052203a2049207b0a202020202020202061636365737328616c6c292066756e20666f6f28293a20537472696e67207b0a20202020202020202020202072657475726e2022666f6f220a20202020202020207d0a202020202020202061636365737328616c6c292066756e2062617228293a20537472696e67207b0a20202020202020202020202072657475726e2022626172220a20202020202020207d0a202020207d0a7d"
access(all) let aUpdateCadence = String.fromUTF8(aUpdateCode.decodeHex()) ?? panic("Problem decoding aUpdateCode")
access(all) var aUpdateHash = ""
access(all) let bUpdateCode = "696d706f727420412066726f6d203078303030303030303030303030303030390a0a61636365737328616c6c2920636f6e74726163742042203a2041207b0a202020200a2020202061636365737328616c6c29207265736f757263652052203a20412e49207b0a202020202020202061636365737328616c6c292066756e20666f6f28293a20537472696e67207b0a20202020202020202020202072657475726e2022666f6f220a20202020202020207d0a202020202020202061636365737328616c6c292066756e2062617228293a20537472696e67207b0a20202020202020202020202072657475726e2022626172220a20202020202020207d0a202020207d0a202020200a2020202061636365737328616c6c292066756e206372656174655228293a204052207b0a202020202020202072657475726e203c2d637265617465205228290a202020207d0a7d"
access(all) let bUpdateCadence = String.fromUTF8(bUpdateCode.decodeHex()) ?? panic("Problem decoding bUpdateCode")
access(all) var bUpdateHash = ""
access(all) let cUpdateCode = "696d706f727420412066726f6d203078303030303030303030303030303030390a696d706f727420422066726f6d203078303030303030303030303030303031300a0a61636365737328616c6c2920636f6e74726163742043207b0a0a2020202061636365737328616c6c29206c65742053746f72616765506174683a2053746f72616765506174680a2020202061636365737328616c6c29206c6574205075626c6963506174683a205075626c6963506174680a0a2020202061636365737328616c6c29207265736f7572636520696e74657266616365204f757465725075626c6963207b0a202020202020202061636365737328616c6c292066756e20676574466f6f46726f6d2869643a2055496e743634293a20537472696e670a202020202020202061636365737328616c6c292066756e2067657442617246726f6d2869643a2055496e743634293a20537472696e670a202020207d0a0a2020202061636365737328616c6c29207265736f75726365204f75746572203a204f757465725075626c6963207b0a202020202020202061636365737328616c6c29206c657420696e6e65723a20407b55496e7436343a20412e527d0a0a2020202020202020696e69742829207b0a20202020202020202020202073656c662e696e6e6572203c2d207b7d0a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e20676574466f6f46726f6d2869643a2055496e743634293a20537472696e67207b0a20202020202020202020202072657475726e2073656c662e626f72726f775265736f75726365286964293f2e666f6f2829203f3f2070616e696328224e6f207265736f7572636520666f756e64207769746820676976656e20494422290a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e2067657442617246726f6d2869643a2055496e743634293a20537472696e67207b0a20202020202020202020202072657475726e2073656c662e626f72726f775265736f75726365286964293f2e6261722829203f3f2070616e696328224e6f207265736f7572636520666f756e64207769746820676976656e20494422290a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e206164645265736f75726365285f20693a2040412e5229207b0a20202020202020202020202073656c662e696e6e65725b692e757569645d203c2d2120690a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e20626f72726f775265736f75726365285f2069643a2055496e743634293a20267b412e497d3f207b0a20202020202020202020202072657475726e202673656c662e696e6e65725b69645d20617320267b412e497d3f0a20202020202020207d0a0a202020202020202061636365737328616c6c292066756e2072656d6f76655265736f75726365285f2069643a2055496e743634293a2040412e523f207b0a20202020202020202020202072657475726e203c2d2073656c662e696e6e65722e72656d6f7665286b65793a206964290a20202020202020207d0a0a202020202020202064657374726f792829207b0a20202020202020202020202064657374726f792073656c662e696e6e65720a20202020202020207d0a202020207d0a0a20202020696e69742829207b0a202020202020202073656c662e53746f7261676550617468203d202f73746f726167652f4f757465720a202020202020202073656c662e5075626c696350617468203d202f7075626c69632f4f757465725075626c69630a0a202020202020202073656c662e6163636f756e742e736176653c404f757465723e283c2d637265617465204f7574657228292c20746f3a2073656c662e53746f7261676550617468290a202020202020202073656c662e6163636f756e742e6c696e6b3c267b4f757465725075626c69637d3e2873656c662e5075626c6963506174682c207461726765743a2073656c662e53746f7261676550617468290a0a20202020202020206c6574206f75746572203d2073656c662e6163636f756e742e626f72726f773c264f757465723e2866726f6d3a2073656c662e53746f726167655061746829210a20202020202020206f757465722e6164645265736f75726365283c2d20422e637265617465522829290a202020207d0a7d"
access(all) let cUpdateCadence = String.fromUTF8(cUpdateCode.decodeHex()) ?? panic("Problem decoding cUpdateCode")
access(all) var cUpdateHash = ""

// Block height different to add to the staging cutoff
access(all) let blockHeightDelta: UInt64 = 10
Expand Down Expand Up @@ -75,6 +79,8 @@ access(all) fun testStageContractSucceeds() {
// Take snapshot as the following test case will stage this same transaction via Host Capability
snapshotHeight = getCurrentBlockHeight()

fooUpdateHash = MigrationContractStaging.getCodeHash(fooUpdateCadence)

let txResult = executeTransaction(
"../transactions/migration-contract-staging/stage_contract.cdc",
["Foo", fooUpdateCadence],
Expand All @@ -92,7 +98,10 @@ access(all) fun testStageContractSucceeds() {

let fooStagedContractCode = getStagedContractCode(contractAddress: fooAccount.address, contractName: "Foo")
?? panic("Problem retrieving result of getStagedContractCode()")
let fooStagedContractHash = getStagedContractCodeHash(contractAddress: fooAccount.address, contractName: "Foo")
?? panic("Problem retrieving result of getStagedContractCodeHash()")
Test.assertEqual(fooUpdateCadence, fooStagedContractCode)
Test.assertEqual(fooUpdateHash, fooStagedContractHash)

let allStagedCodeForFooAccount = getAllStagedContractCodeForAddress(contractAddress: fooAccount.address)
assertStagedContractCodeEqual({ "Foo": fooUpdateCadence}, allStagedCodeForFooAccount)
Expand All @@ -102,7 +111,7 @@ access(all) fun testStageContractSucceeds() {

let evt = events[0] as! MigrationContractStaging.StagingStatusUpdated
Test.assertEqual(fooAccount.address, evt.address)
Test.assertEqual(fooUpdateCadence, evt.code)
Test.assertEqual(fooUpdateHash, evt.code)
Test.assertEqual("Foo", evt.contract)
Test.assertEqual("stage", evt.action)
}
Expand Down Expand Up @@ -153,13 +162,17 @@ access(all) fun testStageContractViaHostCapabilitySucceeds() {

let evt = events[0] as! MigrationContractStaging.StagingStatusUpdated
Test.assertEqual(fooAccount.address, evt.address)
Test.assertEqual(fooUpdateCadence, evt.code)
Test.assertEqual(fooUpdateHash, evt.code)
Test.assertEqual("Foo", evt.contract)
Test.assertEqual("stage", evt.action)

}

access(all) fun testStageMultipleContractsSucceeds() {
aUpdateHash = MigrationContractStaging.getCodeHash(aUpdateCadence)
bUpdateHash = MigrationContractStaging.getCodeHash(bUpdateCadence)
cUpdateHash = MigrationContractStaging.getCodeHash(cUpdateCadence)

// Demonstrating staging multiple contracts on the same host & out of dependency order
let cStagingTxResult = executeTransaction(
"../transactions/migration-contract-staging/stage_contract.cdc",
Expand Down Expand Up @@ -188,17 +201,17 @@ access(all) fun testStageMultipleContractsSucceeds() {
Test.assertEqual(4, events.length)
let cEvt = events[1] as! MigrationContractStaging.StagingStatusUpdated
Test.assertEqual(bcAccount.address, cEvt.address)
Test.assertEqual(cUpdateCadence, cEvt.code)
Test.assertEqual(cUpdateHash, cEvt.code)
Test.assertEqual("C", cEvt.contract)
Test.assertEqual("stage", cEvt.action)
let bEvt = events[2] as! MigrationContractStaging.StagingStatusUpdated
Test.assertEqual(bcAccount.address, bEvt.address)
Test.assertEqual(bUpdateCadence, bEvt.code)
Test.assertEqual(bUpdateHash, bEvt.code)
Test.assertEqual("B", bEvt.contract)
Test.assertEqual("stage", bEvt.action)
let aEvt = events[3] as! MigrationContractStaging.StagingStatusUpdated
Test.assertEqual(aAccount.address, aEvt.address)
Test.assertEqual(aUpdateCadence, aEvt.code)
Test.assertEqual(aUpdateHash, aEvt.code)
Test.assertEqual("A", aEvt.contract)
Test.assertEqual("stage", aEvt.action)

Expand All @@ -212,13 +225,22 @@ access(all) fun testStageMultipleContractsSucceeds() {

let aStagedCode = getStagedContractCode(contractAddress: aAccount.address, contractName: "A")
?? panic("Problem retrieving result of getStagedContractCode()")
let aStagedHash = getStagedContractCodeHash(contractAddress: aAccount.address, contractName: "A")
?? panic("Problem retrieving result of getStagedContractCodeHash()")
let bStagedCode = getStagedContractCode(contractAddress: bcAccount.address, contractName: "B")
?? panic("Problem retrieving result of getStagedContractCode()")
let bStagedHash = getStagedContractCodeHash(contractAddress: bcAccount.address, contractName: "B")
?? panic("Problem retrieving result of getStagedContractCodeHash()")
let cStagedCode = getStagedContractCode(contractAddress: bcAccount.address, contractName: "C")
?? panic("Problem retrieving result of getStagedContractCode()")
let cStagedHash = getStagedContractCodeHash(contractAddress: bcAccount.address, contractName: "C")
?? panic("Problem retrieving result of getStagedContractCodeHash()")
Test.assertEqual(aUpdateCadence, aStagedCode)
Test.assertEqual(bUpdateCadence, bStagedCode)
Test.assertEqual(cUpdateCadence, cStagedCode)
Test.assertEqual(aUpdateHash, aStagedHash)
Test.assertEqual(bUpdateHash, bStagedHash)
Test.assertEqual(cUpdateHash, cStagedHash)

let allStagedCodeForAAccount = getAllStagedContractCodeForAddress(contractAddress: aAccount.address)
let allStagedCodeForBCAccount = getAllStagedContractCodeForAddress(contractAddress: bcAccount.address)
Expand All @@ -238,7 +260,7 @@ access(all) fun testReplaceStagedCodeSucceeds() {
Test.assertEqual(5, events.length)
let evt = events[4] as! MigrationContractStaging.StagingStatusUpdated
Test.assertEqual(fooAccount.address, evt.address)
Test.assertEqual(fooUpdateCadence, evt.code)
Test.assertEqual(fooUpdateHash, evt.code)
Test.assertEqual("Foo", evt.contract)
Test.assertEqual("replace", evt.action)
}
Expand Down Expand Up @@ -410,6 +432,14 @@ access(all) fun getStagedContractCode(contractAddress: Address, contractName: St
return stagedContractCodeResult.returnValue as! String?
}

access(all) fun getStagedContractCodeHash(contractAddress: Address, contractName: String): String? {
let stagedContractCodeResult = executeScript(
"../scripts/migration-contract-staging/get_staged_contract_code_hash.cdc",
[contractAddress, contractName]
)
return stagedContractCodeResult.returnValue as! String?
}

access(all) fun getAllStagedContractCodeForAddress(contractAddress: Address): {String: String} {
let allStagedContractCodeForAddressResult = executeScript(
"../scripts/migration-contract-staging/get_all_staged_contract_code_for_address.cdc",
Expand Down

0 comments on commit 446aeb6

Please sign in to comment.