Skip to content

Commit

Permalink
Merge pull request #6251 from onflow/bastian/evm-setup-heartbeat
Browse files Browse the repository at this point in the history
[Cadence 1.0 migration] Add migration to setup EVM heartbeat resource
  • Loading branch information
turbolent authored Jul 24, 2024
2 parents bb0874e + 9ad5f9c commit beb1c14
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 67 deletions.
27 changes: 27 additions & 0 deletions cmd/util/ledger/migrations/burner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package migrations

import (
coreContracts "github.com/onflow/flow-core-contracts/lib/go/contracts"
"github.com/rs/zerolog"

"github.com/onflow/flow-go/model/flow"
)

func NewBurnerDeploymentMigration(
chainID flow.ChainID,
logger zerolog.Logger,
) RegistersMigration {
address := BurnerAddressForChain(chainID)
return NewDeploymentMigration(
chainID,
Contract{
Name: "Burner",
Code: coreContracts.Burner(),
},
address,
map[flow.Address]struct{}{
address: {},
},
logger,
)
}
14 changes: 14 additions & 0 deletions cmd/util/ledger/migrations/cadence.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,5 +562,19 @@ func NewCadence1Migrations(
)...,
)

switch opts.EVMContractChange {
case EVMContractChangeNone,
EVMContractChangeDeployFull:
// NO-OP
case EVMContractChangeUpdateFull, EVMContractChangeDeployMinimalAndUpdateFull:
migs = append(
migs,
NamedMigration{
Name: "evm-setup-migration",
Migrate: NewEVMSetupMigration(opts.ChainID, log),
},
)
}

return migs
}
56 changes: 0 additions & 56 deletions cmd/util/ledger/migrations/deploy_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ package migrations
import (
"github.com/onflow/cadence"
jsoncdc "github.com/onflow/cadence/encoding/json"
coreContracts "github.com/onflow/flow-core-contracts/lib/go/contracts"
"github.com/rs/zerolog"

evm "github.com/onflow/flow-go/fvm/evm/stdlib"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/model/flow"
)

Expand Down Expand Up @@ -40,56 +37,3 @@ func NewDeploymentMigration(
expectedWriteAddresses,
)
}

func NewBurnerDeploymentMigration(
chainID flow.ChainID,
logger zerolog.Logger,
) RegistersMigration {
address := BurnerAddressForChain(chainID)
return NewDeploymentMigration(
chainID,
Contract{
Name: "Burner",
Code: coreContracts.Burner(),
},
address,
map[flow.Address]struct{}{
address: {},
},
logger,
)
}

func NewEVMDeploymentMigration(
chainID flow.ChainID,
logger zerolog.Logger,
full bool,
) RegistersMigration {

systemContracts := systemcontracts.SystemContractsForChain(chainID)
address := systemContracts.EVMContract.Address

var code []byte
if full {
code = evm.ContractCode(
systemContracts.NonFungibleToken.Address,
systemContracts.FungibleToken.Address,
systemContracts.FlowToken.Address,
)
} else {
code = []byte(evm.ContractMinimalCode)
}

return NewDeploymentMigration(
chainID,
Contract{
Name: systemContracts.EVMContract.Name,
Code: code,
},
address,
map[flow.Address]struct{}{
address: {},
},
logger,
)
}
84 changes: 84 additions & 0 deletions cmd/util/ledger/migrations/evm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package migrations

import (
"fmt"

"github.com/rs/zerolog"

"github.com/onflow/flow-go/fvm/evm/stdlib"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/model/flow"
)

func NewEVMDeploymentMigration(
chainID flow.ChainID,
logger zerolog.Logger,
full bool,
) RegistersMigration {

systemContracts := systemcontracts.SystemContractsForChain(chainID)
address := systemContracts.EVMContract.Address

var code []byte
if full {
code = stdlib.ContractCode(
systemContracts.NonFungibleToken.Address,
systemContracts.FungibleToken.Address,
systemContracts.FlowToken.Address,
)
} else {
code = []byte(stdlib.ContractMinimalCode)
}

return NewDeploymentMigration(
chainID,
Contract{
Name: systemContracts.EVMContract.Name,
Code: code,
},
address,
map[flow.Address]struct{}{
address: {},
},
logger,
)
}

// NewEVMSetupMigration returns a migration that sets up the EVM contract account.
// It performs the same operations as the EVM contract's initializer, calling the function EVM.setupHeartbeat,
// which in turn creates an EVM.Heartbeat resource, and writes it to the account's storage.
func NewEVMSetupMigration(
chainID flow.ChainID,
logger zerolog.Logger,
) RegistersMigration {

systemContracts := systemcontracts.SystemContractsForChain(chainID)
evmContract := systemContracts.EVMContract

tx := flow.NewTransactionBody().
SetScript([]byte(fmt.Sprintf(
`
import EVM from %s
transaction {
prepare() {
EVM.setupHeartbeat()
}
}
`,
evmContract.Address.HexWithPrefix(),
)))

return NewTransactionBasedMigration(
tx,
chainID,
logger,
map[flow.Address]struct{}{
// The function call writes to the EVM contract account
evmContract.Address: {},
// The function call writes to the global account,
// as the function creates a resource, which gets initialized with a UUID
flow.Address{}: {},
},
)
}
9 changes: 8 additions & 1 deletion cmd/util/ledger/util/registers/registers.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,18 @@ func ApplyChanges(
ownerAddress := flow.BytesToAddress([]byte(registerID.Owner))

if _, ok := expectedChangeAddresses[ownerAddress]; !ok {

expectedChangeAddressesArray := zerolog.Arr()
for expectedChangeAddress := range expectedChangeAddresses {
expectedChangeAddressesArray =
expectedChangeAddressesArray.Str(expectedChangeAddress.Hex())
}

// something was changed that does not belong to this account. Log it.
logger.Error().
Str("key", registerID.String()).
Str("actual_address", ownerAddress.Hex()).
Interface("expected_addresses", expectedChangeAddresses).
Array("expected_addresses", expectedChangeAddressesArray).
Hex("value", newValue).
Msg("key is part of the change set, but is for a different account")
}
Expand Down
2 changes: 1 addition & 1 deletion engine/execution/state/bootstrap/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestBootstrapLedger(t *testing.T) {
}

func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) {
expectedStateCommitmentBytes, _ := hex.DecodeString("8d634458df94d3a284d7363686269c31c45b5ddd017215ec0505ea03a5f547d1")
expectedStateCommitmentBytes, _ := hex.DecodeString("483b6a58223d0d93e85bcdf125a224a80d5d7f1260910941e0b3b4bb6121dc56")
expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes)
require.NoError(t, err)

Expand Down
23 changes: 17 additions & 6 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,8 @@ contract EVM {
?? panic("Could not borrow reference to the EVM bridge")
}

/// The Heartbeat resource controls the block production
/// The Heartbeat resource controls the block production.
/// It is stored in the storage and used in the Flow protocol to call the heartbeat function once per block.
access(all)
resource Heartbeat {
/// heartbeat calls commit block proposals and forms new blocks including all the
Expand All @@ -826,13 +827,23 @@ contract EVM {
}
}

/// createHeartBeat creates a heartbeat resource
access(account)
fun createHeartBeat(): @Heartbeat{
return <-create Heartbeat()
/// setupHeartbeat creates a heartbeat resource and saves it to storage.
/// The function is called once during the contract initialization.
///
/// The heartbeat resource is used to control the block production,
/// and used in the Flow protocol to call the heartbeat function once per block.
///
/// The function can be called by anyone, but only once:
/// the function will fail if the resource already exists.
///
/// The resulting resource is stored in the account storage,
/// and is only accessible by the account, not the caller of the function.
access(all)
fun setupHeartbeat() {
self.account.storage.save(<-create Heartbeat(), to: /storage/EVMHeartbeat)
}

init() {
self.account.storage.save(<-create Heartbeat(), to: /storage/EVMHeartbeat)
self.setupHeartbeat()
}
}
6 changes: 3 additions & 3 deletions utils/unittest/execution_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const ServiceAccountPrivateKeySignAlgo = crypto.ECDSAP256
const ServiceAccountPrivateKeyHashAlgo = hash.SHA2_256

// Pre-calculated state commitment with root account with the above private key
const GenesisStateCommitmentHex = "a9e1cdb1870f90ed3b9b7844e0f4f6b48c1a7439041f454785e42eaf6e2a6621"
const GenesisStateCommitmentHex = "a642be06b34bd0f120c49d907f38a8241a94360637cdaf51b36ae46d655b86c8"

var GenesisStateCommitment flow.StateCommitment

Expand Down Expand Up @@ -87,10 +87,10 @@ func genesisCommitHexByChainID(chainID flow.ChainID) string {
return GenesisStateCommitmentHex
}
if chainID == flow.Testnet {
return "69f5c914c2220dcfcc7a267c740e296cf34e50d59878d8ca99c682e65b092857"
return "6d5efa6e328640d727124e2d54febec0ba1fb5b2477f60d0202f555d77470488"
}
if chainID == flow.Sandboxnet {
return "e1c08b17f9e5896f03fe28dd37ca396c19b26628161506924fbf785834646ea1"
}
return "b65ae8f791ef1775ad27c3705622a3e788bce3b053edc20365d7d90e48bebe60"
return "023fc1b2834efce3b86c14544afb7031a2fe253b3d8c3b43fd7fcadc61816186"
}

0 comments on commit beb1c14

Please sign in to comment.