Skip to content

Commit

Permalink
cherry-pick go crypto contract changes
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored and tarakby committed Oct 26, 2024
1 parent 90d7c91 commit f256ad4
Show file tree
Hide file tree
Showing 6 changed files with 401 additions and 28 deletions.
22 changes: 15 additions & 7 deletions fvm/environment/contract_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,34 @@ import (
"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/ast"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/stdlib"

"github.com/onflow/flow-go/fvm/errors"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/trace"
)

// ContractReader provide read access to contracts.
type ContractReader struct {
tracer tracing.TracerSpan
meter Meter

accounts Accounts
tracer tracing.TracerSpan
meter Meter
accounts Accounts
contracts *systemcontracts.SystemContracts
}

func NewContractReader(
tracer tracing.TracerSpan,
meter Meter,
accounts Accounts,
contracts *systemcontracts.SystemContracts,
) *ContractReader {
return &ContractReader{
tracer: tracer,
meter: meter,
accounts: accounts,
tracer: tracer,
meter: meter,
accounts: accounts,
contracts: contracts,
}
}

Expand Down Expand Up @@ -153,6 +157,10 @@ func (reader *ContractReader) GetCode(
[]byte,
error,
) {
if location == stdlib.CryptoContractLocation {
location = reader.contracts.Crypto.Location()
}

contractLocation, ok := location.(common.AddressLocation)
if !ok {
return nil, errors.NewInvalidLocationErrorf(
Expand Down
5 changes: 4 additions & 1 deletion fvm/environment/facade_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/onflow/flow-go/fvm/storage"
"github.com/onflow/flow-go/fvm/storage/snapshot"
"github.com/onflow/flow-go/fvm/storage/state"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/fvm/tracing"
)

Expand Down Expand Up @@ -61,8 +62,9 @@ func newFacadeEnvironment(
accounts := NewAccounts(txnState)
logger := NewProgramLogger(tracer, params.ProgramLoggerParams)
runtime := NewRuntime(params.RuntimeParams)
chain := params.Chain
systemContracts := NewSystemContracts(
params.Chain,
chain,
tracer,
logger,
runtime)
Expand Down Expand Up @@ -128,6 +130,7 @@ func newFacadeEnvironment(
tracer,
meter,
accounts,
systemcontracts.SystemContractsForChain(chain.ChainID()),
),
ContractUpdater: NoContractUpdater{},
Programs: NewPrograms(
Expand Down
98 changes: 98 additions & 0 deletions fvm/evm/stdlib/checking.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package stdlib

import (
"fmt"

"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/interpreter"
)

// checkingInterface is a runtime.Interface implementation
// that can be used for ParseAndCheckProgram.
// It is not suitable for execution.
type checkingInterface struct {
runtime.EmptyRuntimeInterface
SystemContractCodes map[common.Location][]byte
Programs map[runtime.Location]*interpreter.Program
}

var _ runtime.Interface = &checkingInterface{}

func (*checkingInterface) ResolveLocation(
identifiers []runtime.Identifier,
location runtime.Location,
) (
[]runtime.ResolvedLocation,
error,
) {

addressLocation, isAddress := location.(common.AddressLocation)

// if the location is not an address location, e.g. an identifier location
// (`import Crypto`), then return a single resolved location which declares
// all identifiers.
if !isAddress {
return []runtime.ResolvedLocation{
{
Location: location,
Identifiers: identifiers,
},
}, nil
}

if len(identifiers) == 0 {
return nil, fmt.Errorf("no identifiers provided")
}

// return one resolved location per identifier.
// each resolved location is an address contract location
resolvedLocations := make([]runtime.ResolvedLocation, len(identifiers))
for i := range resolvedLocations {
identifier := identifiers[i]
resolvedLocations[i] = runtime.ResolvedLocation{
Location: common.AddressLocation{
Address: addressLocation.Address,
Name: identifier.Identifier,
},
Identifiers: []runtime.Identifier{identifier},
}
}

return resolvedLocations, nil
}

func (r *checkingInterface) GetOrLoadProgram(
location runtime.Location,
load func() (*interpreter.Program, error),
) (
program *interpreter.Program,
err error,
) {
if r.Programs == nil {
r.Programs = map[runtime.Location]*interpreter.Program{}
}

var ok bool
program, ok = r.Programs[location]
if ok {
return
}

program, err = load()

// NOTE: important: still set empty program,
// even if error occurred

r.Programs[location] = program

return
}

func (r *checkingInterface) GetCode(location common.Location) ([]byte, error) {
return r.SystemContractCodes[location], nil
}

func (r *checkingInterface) GetAccountContractCode(location common.AddressLocation) (code []byte, err error) {
return r.SystemContractCodes[location], nil
}
119 changes: 119 additions & 0 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,127 @@ import "FlowToken"
access(all)
contract EVM {

<<<<<<< HEAD
access(all)
event CadenceOwnedAccountCreated(addressBytes: [UInt8; 20])
=======
// Entitlements enabling finer-grained access control on a CadenceOwnedAccount
access(all) entitlement Validate
access(all) entitlement Withdraw
access(all) entitlement Call
access(all) entitlement Deploy
access(all) entitlement Owner
access(all) entitlement Bridge

/// Block executed event is emitted when a new block is created,
/// which always happens when a transaction is executed.
access(all)
event BlockExecuted(
// height or number of the block
height: UInt64,
// hash of the block
hash: [UInt8; 32],
// timestamp of the block creation
timestamp: UInt64,
// total Flow supply
totalSupply: Int,
// all gas used in the block by transactions included
totalGasUsed: UInt64,
// parent block hash
parentHash: [UInt8; 32],
// root hash of all the transaction receipts
receiptRoot: [UInt8; 32],
// root hash of all the transaction hashes
transactionHashRoot: [UInt8; 32],
/// value returned for PREVRANDAO opcode
prevrandao: [UInt8; 32],
)

/// Transaction executed event is emitted every time a transaction
/// is executed by the EVM (even if failed).
access(all)
event TransactionExecuted(
// hash of the transaction
hash: [UInt8; 32],
// index of the transaction in a block
index: UInt16,
// type of the transaction
type: UInt8,
// RLP encoded transaction payload
payload: [UInt8],
// code indicating a specific validation (201-300) or execution (301-400) error
errorCode: UInt16,
// a human-readable message about the error (if any)
errorMessage: String,
// the amount of gas transaction used
gasConsumed: UInt64,
// if transaction was a deployment contains a newly deployed contract address
contractAddress: String,
// RLP encoded logs
logs: [UInt8],
// block height in which transaction was included
blockHeight: UInt64,
/// captures the hex encoded data that is returned from
/// the evm. For contract deployments
/// it returns the code deployed to
/// the address provided in the contractAddress field.
/// in case of revert, the smart contract custom error message
/// is also returned here (see EIP-140 for more details).
returnedData: [UInt8],
/// captures the input and output of the calls (rlp encoded) to the extra
/// precompiled contracts (e.g. Cadence Arch) during the transaction execution.
/// This data helps to replay the transactions without the need to
/// have access to the full cadence state data.
precompiledCalls: [UInt8],
/// stateUpdateChecksum provides a mean to validate
/// the updates to the storage when re-executing a transaction off-chain.
stateUpdateChecksum: [UInt8; 4]
)

access(all)
event CadenceOwnedAccountCreated(address: String)

/// FLOWTokensDeposited is emitted when FLOW tokens is bridged
/// into the EVM environment. Note that this event is not emitted
/// for transfer of flow tokens between two EVM addresses.
/// Similar to the FungibleToken.Deposited event
/// this event includes a depositedUUID that captures the
/// uuid of the source vault.
access(all)
event FLOWTokensDeposited(
address: String,
amount: UFix64,
depositedUUID: UInt64,
balanceAfterInAttoFlow: UInt
)

/// FLOWTokensWithdrawn is emitted when FLOW tokens are bridged
/// out of the EVM environment. Note that this event is not emitted
/// for transfer of flow tokens between two EVM addresses.
/// similar to the FungibleToken.Withdrawn events
/// this event includes a withdrawnUUID that captures the
/// uuid of the returning vault.
access(all)
event FLOWTokensWithdrawn(
address: String,
amount: UFix64,
withdrawnUUID: UInt64,
balanceAfterInAttoFlow: UInt
)

/// BridgeAccessorUpdated is emitted when the BridgeAccessor Capability
/// is updated in the stored BridgeRouter along with identifying
/// information about both.
access(all)
event BridgeAccessorUpdated(
routerType: Type,
routerUUID: UInt64,
routerAddress: Address,
accessorType: Type,
accessorUUID: UInt64,
accessorAddress: Address
)
>>>>>>> dd533f6ece (translate Crypto identifier location to chain-specific Crypto contract)

/// EVMAddress is an EVM-compatible address
access(all)
Expand Down
Loading

0 comments on commit f256ad4

Please sign in to comment.